ユーザーが「X」または「閉じる」ボタンをクリックしたことを知る方法は?


94

MSDN CloseReason.UserClosingで、ユーザーがフォームを閉じることにしたことがわかりましたが、Xボタンをクリックする場合も閉じるボタンをクリックする場合も同じです。では、コードでこれら2つをどのように区別できますか?

皆さんありがとう。


2
どの閉じるボタンですか?
ブライアンR.ボンディ

たとえば、「ALT + F4」で閉じる
ボーン、


@オリバー同じ質問ではありません。
Ctrl S

回答:


95

WinFormsを要求していると想定すると、FormClosing()イベントを使用できます。イベントFormClosing()は、フォームが閉じられるときにトリガーされます。

ユーザーがXまたはCloseButtonをクリックしたかどうかを検出するには、送信者オブジェクトを介してそれを取得できます。たとえば、senderをButtonコントロールとしてキャストし、その名前が「CloseButton」などであることを確認してください。

private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
    if (string.Equals((sender as Button).Name, @"CloseButton"))
        // Do something proper to CloseButton.
    else
        // Then assume that X has been clicked and act accordingly.
}

それ以外の場合は、MDIContainerFormを閉じる前にすべてのMdiChildrenを閉じる、または保存されていない変更のイベントチェックなど、FormClosingイベントに固有の何かを実行したかったため、XまたはCloseButtonがクリックされたかどうかを区別する必要はありませんでした。私によると、これらの状況下では、どちらのボタンとも区別する必要はありません。

ALT+で閉じるF4と、FormClosing()イベントがトリガーされます。フォームに閉じるようにメッセージが送信されるためです。イベントをキャンセルするには、

FormClosingEventArgs.Cancel = true. 

この例では、これは次のように変換されます。

e.Cancel = true.

FormClosing()イベントとFormClosed()イベントの違いに注意してください。

FormClosingは、フォームが閉じるメッセージを受信したときに発生し、閉じる前に何かする必要があるかどうかを確認します。

FormClosedは、フォームが実際に閉じたときに発生するため、閉じた後に発生します。

これは役に立ちますか?


はい、「キャスト」のアイデアに感謝します。Delphi7でこのテクニックを使用していましたが、C#で同じことをするのを忘れていました
Bohn

これは、Delphiから.NETへの移植です。=)私は助けてよかったです!
Marcouillerが

1
このコードを使用すると、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というメッセージが表示されます。
ネイトS.

33
これは間違っています。フォーム自体であるため、送信者をボタンにキャストできません。これは例外をスローします。
Xtro、2015年

1
これは誤った答えです。これには賛成しないでください。
Najeeb

79

CloseReasonあなたはMSDNで見つけ列挙は、単にユーザーがアプリを閉じた、またはそれがシャットダウンによるものであったか、など、タスクマネージャによって閉じられているかどうかをチェックするためのものであり...

理由に応じて、次のようなさまざまなアクションを実行できます。

void Form_FormClosing(object sender, FormClosingEventArgs e)
{
    if(e.CloseReason == CloseReason.UserClosing)
        // Prompt user to save his data

    if(e.CloseReason == CloseReason.WindowsShutDown)
        // Autosave and clear up ressources
}

しかし、ご想像のとおり、xボタンをクリックするか、タスクバーを右クリックして[閉じる]をクリックするか、を押すAlt F4などの違いはありません。すべて、CloseReason.UserClosing何らかの理由で終了します。


11
標準のClose();を使用します。CloseReason.UserClosingをトリガーするようです。なぜだかわかりません。
Dan W

親が閉じられているときにではなく、フォーム上のユーザーアクションによってMDI子フォームの閉じをブロックしようとするときに、これが便利であることがわかりました。
スティーブペティファー2014

1
これは質問には答えません。問題をさらに列挙するだけです。
Robert Koernke 2017

イベントをメソッドにどのようにバインドしますか?
user2924019

43

「X」ボタンDialogResult.Cancelは別のオプションとして登録されるため、DialogResult

フォームに複数のボタンがある場合は、おそらくすでに異なる DialogResultそれぞれにているため、各ボタンの違いを確認する手段が提供されます。

(例:btnSubmit.DialogResult = DialogResult.OKbtnClose.DialogResult = Dialogresult.Abort

    public Form1()
    {
        InitializeComponent();

        this.FormClosing += Form1_FormClosing;
    }

    /// <summary>
    /// Override the Close Form event
    /// Do something
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
    {
        //In case windows is trying to shut down, don't hold the process up
        if (e.CloseReason == CloseReason.WindowsShutDown) return;

        if (this.DialogResult == DialogResult.Cancel)
        {
            // Assume that X has been clicked and act accordingly.
            // Confirm user wants to close
            switch (MessageBox.Show(this, "Are you sure?", "Do you still want ... ?", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
            {
                //Stay on this form
                case DialogResult.No:
                    e.Cancel = true;
                    break;
                default:
                    break;
            }
        }
    }

1
私の場合、これは受け入れられた答えよりも便利です。「X」にはDialogResult.Cancelが割り当てられているため、キャンセルボタンに他の値を割り当てると、それらを簡単に区別して適切に処理できます。
MickeyfAgain_BeforeExitOfSO

3
これは私の場合は機能しません。「X」を押すと、DialogResult残りNoneます。何が問題でしょうか?
Bhaskar 2015年

1
@Bhaskar、ダイアログをインスタンス化するときは、ダイアログの各ボタンに適切なDialogResultを設定してください。上記の例を提供しましたが、ダイアログ宣言を示すコードブロックを作成しませんでした。
AlexScript 2017

@Bhaskar:を押すXDialogResultCancelではなくが含まれますNoneNoneボタンへの割り当ては、その.DialogResultプロパティをまったく設定しないことと同じであり、form.Close()ボタンのイベントハンドラーから呼び出すと、form.DialogResultが含まれますCancel。フォームを閉じるボタン以外の値NoneまたはCancelすべてのボタンに値を割り当てるだけで、目的の区別が可能になります。
mklement0

9

XボタンをクリックするClose()か、コードを呼び出すことによってフォームが閉じられたかどうかを検出するにはどうすればよいですか?

ユーザーがタイトルバーのXボタンをクリックするか、Alt + F4を使用してフォームを閉じるか、システムメニューを使用してフォームを閉じるか、Close()メソッドを呼び出すことによってフォームが閉じられるため、フォームを閉じるイベント引数の閉じる理由に依存することはできません。上記の場合、クローズ理由はユーザーによってクローズされますこれは望ましい結果ではありません。

フォームがXボタンまたはCloseメソッドのどちらで閉じられたかを区別するには、次のオプションのいずれかを使用できます。

  • 取り扱いWM_SYSCOMMANDと確認SC_CLOSEフラグ、設定します。
  • を確認しStackTraceて、フレームにCloseメソッド呼び出しが含まれているかどうかを確認してください。

例1-ハンドル WM_SYSCOMMAND

public bool ClosedByXButtonOrAltF4 {get; private set;}
private const int SC_CLOSE = 0xF060;
private const int WM_SYSCOMMAND = 0x0112;
protected override void WndProc(ref Message msg)
{
    if (msg.Msg == WM_SYSCOMMAND && msg.WParam.ToInt32() == SC_CLOSE)
        ClosedByXButtonOrAltF4 = true;
    base.WndProc(ref msg);
}
protected override void OnShown(EventArgs e)
{
    ClosedByXButtonOrAltF4 = false;
}   
protected override void OnFormClosing(FormClosingEventArgs e)
{
    if (ClosedByXButtonOrAltF4)
        MessageBox.Show("Closed by X or Alt+F4");
    else
        MessageBox.Show("Closed by calling Close()");
}

例2-StackTraceの確認

protected override void OnFormClosing(FormClosingEventArgs e)
{
    if (new StackTrace().GetFrames().Any(x => x.GetMethod().Name == "Close"))
        MessageBox.Show("Closed by calling Close()");
    else
        MessageBox.Show("Closed by X or Alt+F4");
}

1
よくできました。あなたがパーティーに遅れたのは残念です。すでに高く投票されている古い回答と競争するのは困難です。
mklement0

1
@ mklement0今後のユーザーに役立つと思います。他の回答ではなく問題を正しく解決できるため、回答を投稿しました。このビュー数と非常に投票された(動作しない)回答を持つ質問にはかなり奇妙です!
Reza Aghaei

7

フォームが閉じている場合(アプリケーションが特定のフォームに添付されていない場合)、アプリケーションをいつ閉じるかを決定します。

    private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (Application.OpenForms.Count == 0) Application.Exit();
    }

5

私のアプリケーションでは常に、フォームのCloseメソッドを使用しています。このメソッドは、exitボタンからのalt + x、alt + f4、または別のフォームの終了イベントが開始されたことをキャッチします。mstrClsTitle = "grmRexcel"この場合、すべてのクラスのクラス名はプライベート文字列として定義されています。このメソッドは、フォームのクローズメソッドとフォームのクローズメソッドを呼び出すExitメソッドです。フォームのクローズ方法-についての声明もありthis.FormClosing = My Form Closing Form Closing method nameます。

このためのコード:

namespace Rexcel_II
{
    public partial class frmRexcel : Form
    {
        private string mstrClsTitle = "frmRexcel";

        public frmRexcel()
        {
            InitializeComponent();

            this.FormClosing += frmRexcel_FormClosing;
        }

        /// <summary>
        /// Handles the Button Exit Event executed by the Exit Button Click
        /// or Alt + x
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExit_Click(object sender, EventArgs e)
        {            
            this.Close();        
        }


        /// <summary>
        /// Handles the Form Closing event
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmRexcel_FormClosing(object sender, FormClosingEventArgs e)
        {

            // ---- If windows is shutting down, 
            // ---- I don't want to hold up the process
            if (e.CloseReason == CloseReason.WindowsShutDown) return;
            {

                // ---- Ok, Windows is not shutting down so
                // ---- either btnExit or Alt + x or Alt + f4 has been clicked or
                // ---- another form closing event was intiated
                //      *)  Confirm user wants to close the application
                switch (MessageBox.Show(this, 
                                    "Are you sure you want to close the Application?",
                                    mstrClsTitle + ".frmRexcel_FormClosing",
                                    MessageBoxButtons.YesNo, MessageBoxIcon.Question))
                {

                    // ---- *)  if No keep the application alive 
                    //----  *)  else close the application
                    case DialogResult.No:
                        e.Cancel = true;
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

2

次のようなデザインからイベントハンドラーを追加してみてください。デザインビューでフォームを開く、プロパティウィンドウを開く、またはF4キーを押し、イベントツールバーボタンをクリックしてFormオブジェクトのイベントを表示し、[動作]グループでFormClosingイベントを見つけてダブルクリックします。リファレンス:https : //social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral


1
if (this.DialogResult == DialogResult.Cancel)
        {

        }
        else
        {
            switch (e.CloseReason)
            {
                case CloseReason.UserClosing:
                    e.Cancel = true;
                    break;
            }
        }

ユーザーがフォームの「X」または閉じるボタンをクリックしたときに条件が実行されるかどうか。elseは、ユーザーが他の目的でAlt + f4をクリックしたときに使用できます


1
namespace Test
{
    public partial class Member : Form
    {
        public Member()
        {
            InitializeComponent();
        }

        private bool xClicked = true;

        private void btnClose_Click(object sender, EventArgs e)
        {
            xClicked = false;
            Close();
        }

        private void Member_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (xClicked)
            {
                // user click the X
            } 
            else 
            {
                // user click the close button
            }
        }
    }
}

1

私はDialogResult-Solutionをより単純なものとして同意します。

ただし、VB.NETでは、CloseReason-Property を取得するには型キャストが必要です。

    Private Sub MyForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing

        Dim eCast As System.Windows.Forms.FormClosingEventArgs
        eCast = TryCast(e, System.Windows.Forms.FormClosingEventArgs)
        If eCast.CloseReason = Windows.Forms.CloseReason.None Then
            MsgBox("Button Pressed")
        Else
            MsgBox("ALT+F4 or [x] or other reason")
        End If

    End Sub

0

また、フォームの「InitializeComponent()」メソッド内にクロージング関数を登録する必要がありました。

private void InitializeComponent() {
// ...
this.FormClosing += FrmMain_FormClosing;
// ...
}

私の "FormClosing"関数は与えられた答え(https://stackoverflow.com/a/2683846/3323790)に似ています

private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) {
    if (e.CloseReason == CloseReason.UserClosing){
        MessageBox.Show("Closed by User", "UserClosing");
    }

    if (e.CloseReason == CloseReason.WindowsShutDown){
        MessageBox.Show("Closed by Windows shutdown", "WindowsShutDown");
    }
}

もう1つ言及する必要があります。「FormClosing」の後に発生する「FormClosed」関数もあります。この機能を使用するには、以下のように登録してください。

this.FormClosed += MainPage_FormClosed;

private void MainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}

0

私はこのようなことをしました。

private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if ((sender as Form).ActiveControl is Button)
        {
            //CloseButton
        }
        else
        {
            //The X has been clicked
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.