我注意到我在应用程序中打开的窗口中出现了令人不安的行为:关闭窗口本身很长时间后,命令和(最引人注目的是)它们的“可以执行”方法才被触发。
这是我倾向于做事的简化示例:
public class AllMaxThemedWindow : DevExpress.Xpf.Core.ThemedWindow, INotifyPropertyChanged
{
public static DependencyProperty ShowMinimizeButtonProperty = DependencyProperty.Register("ShowMinimizeButton", typeof(Boolean), typeof(AllMaxThemedWindow), new PropertyMetadata(true));
public Boolean ShowMinimizeButton
{
get => (Boolean)GetValue(ShowMinimizeButtonProperty);
set => SetValue(ShowMinimizeButtonProperty, value);
}
//Maximize and Close DPs as well
public AllMaxThemedWindow()
{
Loaded += AllMaxThemedWindow_Loaded;
}
private void AllMaxThemedWindow_Loaded(Object sender, RoutedEventArgs e)
{
if (!ShowMinimizeButton)
{
var button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_Minimize.ToString());
button.Visibility = Visibility.Collapsed;
}
//Maximize and Close checks as well
//If neither maximize nor minimize is allowed, then prevent the system menu from being shown (via button or right-click).
if (!ShowMaximizeButton && !ShowMinimizeButton)
{
var hwnd = new WindowInteropHelper(this).Handle;
NativeMethods.SetWindowLong(hwnd, GWL_STYLE, NativeMethods.GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
}
}
<atw:AllMaxThemedWindow x:Class="Antero.Windows.ThemedWindowInstance">
<atw:AllMaxThemedWindow.DataContext>
<vm:ThemedWindowInstanceViewModel />
</atw:AllMaxThemedWindow.DataContext>
</atw:AllMaxThemedWindow>
//...opened this way in a view model's button command handler
new ThemedWindowInstance().ShowDialog(true);
除此之外,没有什么特别的事情发生。最终,它只是一个Window
,并且该窗口已作为模式打开。然后,用户单击X
将其关闭。
那是坏事发生的时候。例如,在一个窗口上有一个Save
按钮,该按钮绑定到具有“可以执行”方法的命令(在其视图模型中)。在关闭窗口很长时间之后,该方法将继续被触发。实际上,它似乎永远会触发。
我来自WinForms领域,所以我习惯做Dispose
之类的事情,但是在WPF中我似乎无法使用。那么,在WPF世界中,到底是什么让窗口(或其视图模型)永远悬而未决?
答案 0 :(得分:-1)
您的ICommand实现应实现CanExecuteChanged事件。而且,您应该在每次执行条件实际更改时触发此事件。通常,ICommand实现具有NotifyCanExecuteChanged方法。
public class DelegateCommand : ICommand
{
private readonly Action<object> _execute = null;
private readonly Predicate<object> _canExecute = null;
#region Constructors
public DelegateCommand(Action<object> execute)
: this(execute, null) { }
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExecute != null ? _canExecute(parameter) : true;
}
public void Execute(object parameter)
{
if (_execute != null)
_execute(parameter);
}
public void NotifyCanExecuteChanged()
{
if(CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
#endregion
}