WPF中的Button.IsCancel属性是如何工作的?

34

取消按钮的基本思路是允许通过按下Esc键关闭窗口。

您可以将“取消”按钮的IsCancel属性设置为true,从而使“取消”按钮在不处理Click事件的情况下自动关闭对话框。

来源:Programming WPF (Griffith, Sells)

因此,这应该可以工作。

<Window>
<Button Name="btnCancel" IsCancel="True">_Close</Button>
</Window>

但是我期望的行为并没有实现。父窗口是由Application.StartupUri属性指定的主应用程序窗口。有效的方法是:

<Button Name="btnCancel" IsCancel=True" Click="CloseWindow">_Close</Button>

private void CloseWindow(object sender, RoutedEventArgs) 
{
    this.Close();
}
  • 如果 Window 是普通窗口或对话框,IsCancel 的行为是否不同?只有在调用 ShowDialog 后,IsCancel 才能按照其广告所述地正常工作吗?
  • 在按下 Escape 键时,是否需要为具有 IsCancel 设置为 true 的按钮指定显式的 Click 处理程序才能关闭窗口?
4个回答

35

是的,这只适用于对话框,因为普通窗口没有“取消”的概念,这与WinForms中在ShowDialog中返回DialogResult.Cancel相同。

如果你想用esc关闭一个窗口,你可以在窗口上添加一个PreviewKeyDown处理程序,在其中检测是否是Key.Escape,然后关闭该窗体:

public MainWindow()
{
    InitializeComponent();

    this.PreviewKeyDown += new KeyEventHandler(CloseOnEscape);
}

private void CloseOnEscape(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Escape)
        Close();
}

17

我们可以进一步采用Steve的答案,创建一个附加属性,为任何窗口提供“关闭时转义”的功能。 只需编写一次该属性并在任何窗口中使用即可。 只需将以下内容添加到窗口的XAML中:

yournamespace:WindowService.EscapeClosesWindow="True"

这里是该属性的代码:

using System.Windows;
using System.Windows.Input;

/// <summary>
/// Attached behavior that keeps the window on the screen
/// </summary>
public static class WindowService
{
   /// <summary>
   /// KeepOnScreen Attached Dependency Property
   /// </summary>
   public static readonly DependencyProperty EscapeClosesWindowProperty = DependencyProperty.RegisterAttached(
      "EscapeClosesWindow",
      typeof(bool),
      typeof(WindowService),
      new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnEscapeClosesWindowChanged)));

   /// <summary>
   /// Gets the EscapeClosesWindow property.  This dependency property 
   /// indicates whether or not the escape key closes the window.
   /// </summary>
   /// <param name="d"><see cref="DependencyObject"/> to get the property from</param>
   /// <returns>The value of the EscapeClosesWindow property</returns>
   public static bool GetEscapeClosesWindow(DependencyObject d)
   {
      return (bool)d.GetValue(EscapeClosesWindowProperty);
   }

   /// <summary>
   /// Sets the EscapeClosesWindow property.  This dependency property 
   /// indicates whether or not the escape key closes the window.
   /// </summary>
   /// <param name="d"><see cref="DependencyObject"/> to set the property on</param>
   /// <param name="value">value of the property</param>
   public static void SetEscapeClosesWindow(DependencyObject d, bool value)
   {
      d.SetValue(EscapeClosesWindowProperty, value);
   }

   /// <summary>
   /// Handles changes to the EscapeClosesWindow property.
   /// </summary>
   /// <param name="d"><see cref="DependencyObject"/> that fired the event</param>
   /// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>
   private static void OnEscapeClosesWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   {
      Window target = (Window)d;
      if (target != null)
      {
         target.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(Window_PreviewKeyDown);
      }
   }

   /// <summary>
   /// Handle the PreviewKeyDown event on the window
   /// </summary>
   /// <param name="sender">The source of the event.</param>
   /// <param name="e">A <see cref="KeyEventArgs"/> that contains the event data.</param>
   private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
   {
      Window target = (Window)sender;

      // If this is the escape key, close the window
      if (e.Key == Key.Escape)
         target.Close();
   }
}

3
是的。附加属性仍然不能立即在我的脑海中“点击”。 - Gishu

6

这不太对吧... MSDN说:当你将一个按钮的IsCancel属性设置为true时,你创建了一个已经在AccessKeyManager中注册的按钮。当用户按下ESC键时,该按钮被激活。 所以你需要在你的代码后台添加一个处理程序 你不需要任何附加属性或类似的东西


3
MSDN 不是完全的 - 可以在这里查看代码: http://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/Button.cs,274 当按下一个按钮时,如果没有分配Command并且IsCancel被设置,那么DialogCancel会自动执行(在OnClick句柄完成后)。 - Govert

3

是的,这是正确的。在WPF的Windows应用程序中,有AcceptButton和CancelButton。但是有一点需要注意,如果您将控件的可见性设置为false,则它不会按预期工作。因此,在WPF中,您需要将其可见性设置为true。例如:(对于取消按钮不起作用,因为这里的可见性为false)

<Button x:Name="btnClose" Content="Close" IsCancel="True" Click="btnClose_Click" Visibility="Hidden"></Button> 

所以,您需要制作它:
<Button x:Name="btnClose" Content="Close" IsCancel="True" Click="btnClose_Click"></Button>

然后您需要在代码后台文件中编写 btnClose_Click
private void btnClose_Click (object sender, RoutedEventArgs e)
    { this.Close(); }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接