C# OnFormClosing和e.CloseReason
我有一个表单,上面有两个按钮“取消”和“确定”。在“Cancel”按钮的处理程序中,我执行需要执行的回滚操作,然后调用C# OnFormClosing和e.CloseReason,c#,winforms,C#,Winforms,我有一个表单,上面有两个按钮“取消”和“确定”。在“Cancel”按钮的处理程序中,我执行需要执行的回滚操作,然后调用this.Close()。在“OK”按钮的处理程序中,我执行所有需要执行的操作,然后调用this.Close() 因此,我现在意识到,用户也可能单击表单右上角的“X”图标来关闭表单。我应该像对待“取消”按钮一样对待它,但我没有办法覆盖“X”按钮。我能做的最好的事情就是为OnFormClosing事件添加一个处理程序 但我仍然感到困惑,不确定处理这个问题的最佳方式是什么。表单也可以
this.Close()
。在“OK”按钮的处理程序中,我执行所有需要执行的操作,然后调用this.Close()
因此,我现在意识到,用户也可能单击表单右上角的“X”图标来关闭表单。我应该像对待“取消”按钮一样对待它,但我没有办法覆盖“X”按钮。我能做的最好的事情就是为OnFormClosing
事件添加一个处理程序
但我仍然感到困惑,不确定处理这个问题的最佳方式是什么。表单也可以关闭还有许多其他原因(如ALT-F4或Windows关闭),我希望将所有这些都视为“取消”按钮
但是,无论我是通过单击“X”、“close”(最终调用this.close()
)还是“OK”(最终调用this.close()
)来关闭表单,e.CloseReason
的值是相同的(UserClosing
),而sender
的值也是相同的,因此我无法区分
如果表单因单击“确定”按钮以外的任何原因关闭,实现回滚的最佳方法是什么?在某些表单上,我通过使用Win32函数隐藏X按钮来解决问题-不知道它是否适合您的情况,但代码如下
/// <summary>
/// Win32 function to get window information
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="nIndex">Information to get</param>
/// <returns>Required Window Information</returns>
[DllImport("user32.dll")]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
/// <summary>
/// Code to get/set Style for window
/// </summary>
private const int GWL_STYLE = -16;
/// <summary>
/// System menu bit
/// </summary>
private const int WS_SYSMENU = 0x80000;
/// <summary>
/// Hide close button on window
/// </summary>
/// <param name="w">Window to set</param>
/// <remarks>Actually removes all of system menu from window title bar</remarks>
public static void HideCloseButton(Window w)
{
var hwnd = new WindowInteropHelper(w).Handle;
NativeMethods.SetWindowLong(hwnd, GWL_STYLE, NativeMethods.GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
/// <summary>
/// Show close button on window
/// </summary>
/// <param name="w">Window to set</param>
/// <remarks>Actually shows all of system menu from window title bar</remarks>
public static void ShowCloseButton(Window w)
{
var hwnd = new WindowInteropHelper(w).Handle;
NativeMethods.SetWindowLong(hwnd, GWL_STYLE, NativeMethods.GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
}
//
///获取窗口信息的Win32函数
///
///窗把手
///要获取的信息
///所需窗口信息
[DllImport(“user32.dll”)]
内部静态外部int GetWindowLong(IntPtr hWnd,int nIndex);
///
///获取/设置窗口样式的代码
///
私有常量int GWL_STYLE=-16;
///
///系统菜单位
///
私有常量int WS_SYSMENU=0x80000;
///
///隐藏窗口上的关闭按钮
///
///设置窗口
///实际上从窗口标题栏中删除所有系统菜单
公共静态无效隐藏关闭按钮(窗口w)
{
var hwnd=新的WindowInteropHelper(w).Handle;
NativeMethods.SetWindowLong(hwnd,GWL_样式,NativeMethods.GetWindowLong(hwnd,GWL_样式)&~WS_系统菜单);
}
///
///在窗口上显示关闭按钮
///
///设置窗口
///实际显示窗口标题栏中的所有系统菜单
公共静态无效显示关闭按钮(窗口w)
{
var hwnd=新的WindowInteropHelper(w).Handle;
NativeMethods.SetWindowLong(hwnd,GWL_样式,NativeMethods.GetWindowLong(hwnd,GWL_样式)| WS_系统菜单);
}
您只需在OK按钮处理程序中设置一个布尔值,然后在OnFormClosing()覆盖中检查该布尔值,如下所示:
public partial class Form1: Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (!this.isClosingViaOkButton)
{
// ...do your rollback here.
MessageBox.Show("Rolling back");
}
}
private void okButton_Click(object sender, EventArgs e)
{
// ...do your committing here.
this.isClosingViaOkButton = true;
this.Close();
}
private bool isClosingViaOkButton;
}
作为替代方案,您可以在OnFormClosing()中执行这两项操作,而不是在OK按钮处理程序中提交并在OnFormClosing()中回滚,如下所示:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (this.isClosingViaOkButton)
{
// ...do your committing.
}
else
{
// ...do your rollback.
}
}
我自己更喜欢这种方法。您真的不需要
CloseReason
,是吗
private bool _closing;
private void Form1_FormClosing( object sender, FormClosingEventArgs e )
{
e.Cancel = !_closing; // prevent form from being closed
}
// inside OK and Cancel button handler
...
_closing = true;
Close();
请阅读DialogResult属性。如果要创建自定义原因信息,只需在表单中创建其他属性。这不是对话框,而是使用form.Show()显示的普通表单。DialogResult是没有意义的。我在window loaded事件中调用它:private void window_loaded(object sender,RoutedEventArgs e){LibW2.HideCloseButton(this);}谢谢,但我不希望“x”按钮不可见。这将破坏我的应用程序的一致性。这似乎是在回避问题,而不是解决问题。