Kullanıcının "X" veya "Kapat" düğmesini tıkladığını nasıl anlarım?


98

MSDN'de CloseReason.UserClosing, kullanıcının formu kapatmaya karar verdiğini öğrendim ama sanırım hem X düğmesine hem de kapat düğmesine tıklamak için aynı şey geçerli. Öyleyse, kodumda bu ikisini nasıl ayırt edebilirim?

Hepinize teşekkürler.


2
hangi kapat düğmesini kastediyorsunuz?
Brian R. Bondy

örneğin "ALT + F4" ile kapatma
Bohn


@Oliver Aynı soru değil.
Ctrl S

Yanıtlar:


96

WinForms istediğinizi varsayarsak, FormClosing () olayını kullanabilirsiniz . FormClosing () olayı, bir formun kapatılması gerektiğinde tetiklenir.

Kullanıcının X'i mi yoksa CloseButton'ınızı mı tıklattığını tespit etmek için, bunu gönderen nesnesi üzerinden alabilirsiniz. Göndereni bir Düğme kontrolü olarak atmaya çalışın ve örneğin "CloseButton" adını doğrulayın.

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.
}

Aksi takdirde, MDIContainerForm'u kapatmadan önce tüm MdiChildren'leri kapatmak veya kaydedilmemiş değişiklikler için olay denetimi gibi FormClosing olayında belirli bir şey gerçekleştirmek istediğimden, X veya CloseButton'ın tıklanıp tıklanmadığını hiçbir zaman ayırt etmem gerekmedi. Bu koşullar altında, bana göre, iki düğmeden de ayırt etmemize gerek yok.

ALT+ F4İle kapatma aynı zamanda FormClosing () olayını tetikler, çünkü Form'a kapatılmasını söyleyen bir mesaj gönderir. Etkinliği ayarlayarak iptal edebilirsiniz.

FormClosingEventArgs.Cancel = true. 

Örneğimizde bu, şu şekilde tercüme edilir:

e.Cancel = true.

FormClosing () ve FormClosed () olayları arasındaki farka dikkat edin .

FormClosing, form kapatılacak mesajı aldığında ve kapatılmadan önce yapması gereken bir şey olup olmadığını doğruladığında gerçekleşir.

FormClosed, form gerçekten kapatıldığında, bu nedenle kapatıldıktan sonra gerçekleşir.

Bu yardımcı olur mu?


Evet, "Cast" fikri için teşekkürler, bu tekniği Delphi 7 ile kullandım ama aynısını C #
Bohn

1
Bu kodu kullandığımda 'Nesne başvurusu bir nesnenin örneğine ayarlanmadı' mesajı alıyorum.
Nate S.

35
Bu yanlış. Göndereni düğmeye atamazsınız çünkü bu formun kendisidir. Bu istisnai bir durum oluşturur.
Xtro

2
Lütfen bunun YANLIŞ bir cevap olduğunu unutmayın. Lütfen bunu yükseltmeyin.
Najeeb

1
Kullanıcının cevabına göz atın @Reza Aghaei
Najeeb

79

CloseReasonEğer MSDN üzerinde bulunan numaralandırma sadece kullanıcının uygulamayı kapalı ya da bir kapatma kaynaklandığını veya vb görev yöneticisi tarafından kapatılmış olup olmadığını kontrol etmek amacıyla bir ...

Nedenine göre farklı eylemler yapabilirsiniz, örneğin:

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
}

Ancak tahmin ettiğiniz gibi, x düğmesine tıklamakla görev çubuğuna sağ tıklamakla 'kapat'a tıklamak ya da basmak Alt F4vb. Arasında hiçbir fark yoktur CloseReason.UserClosing.


11
Standart Kapat () kullanarak; CloseReason.UserClosing'i benim için tetikliyor gibi görünüyor. Emin değilim neden.
Dan W

Bunu, formdaki kullanıcı eylemiyle bir MDI alt formunun kapatılmasını engellemeye çalışırken ancak üst öğe kapatılırken engellemeye çalışırken faydalı buldum.
Steve Pettifer

1
Bu soruya cevap vermez, sadece konuyu daha ayrıntılı olarak sıralayın.
Robert Koernke

Olayı yönteme nasıl bağlarsınız?
user2924019

44

"X" düğmesi kaydedildiği DialogResult.Canceliçin başka bir seçenek de DialogResult.

Formunuzda birden çok düğme varsa, muhtemelen zaten DialogResulther biriyle farklı ' ler ilişkilendiriyorsunuzdur ve bu, size her düğme arasındaki farkı anlamanız için araçlar sağlayacaktır.

(Örnek: btnSubmit.DialogResult = DialogResult.OK, btnClose.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
Benim durumumda bu, kabul edilen cevaptan daha yararlıdır. 'X'e DialogResult.Cancel atandığından, iptal düğmesine başka bir değer atamak onları kolayca ayırt eder ve işleri uygun şekilde ele alır.
MickeyfAgain_BeforeExitOfSO

3
Bu benim durumumda çalışmıyor. 'X'e basıldığında DialogResultkalır None. Sorun ne olabilir?
Bhaskar

1
@Bhaskar, diyaloğunuzu oluşturduğunuzda, diyaloğunuzdaki her düğmeye uygun DialogResult'u ayarladığınızdan emin olun. Yukarıda bir örnek vermiştim, ancak Dialog bildirimini göstermek için bir kod bloğu oluşturmadım.
AlexScript

@Bhaskar: basılması Xmarkaları DialogResultihtiva Canceldeğil None. Düğmenize atamak None, .DialogResultözelliğini hiç ayarlamamakla aynıdır ve form.Close()düğmenizin olay işleyicisinden ararsanız , düğmeyi form.DialogResultiçerir Cancel. Tüm form kapatma düğmelerinizden başka Noneveya Cancelbunlara yalnızca bir değer atamak , istediğiniz ayrımı yapmanıza olanak tanır.
mklement0

15

Formun X düğmesine tıklayarak veya Close()kodla arayarak kapanıp kapanmadığı nasıl anlaşılır ?

Form kapatma olay bağımsız değişkenlerinin yakın nedenine güvenemezsiniz, çünkü kullanıcı başlık çubuğundaki X düğmesine tıklarsa veya Alt + F4 kullanarak formu kapatırsa veya formu kapatmak için sistem menüsünü kullanırsa veya formu çağırarak kapatılırsa Close(), tümü Yukarıdaki durumlarda, yakın sebep Kullanıcı Tarafından Kapatılacak ve bu da arzu edilmeyen bir sonuç olacaktır.

Formun X düğmesiyle mi yoksa Closeyöntemle mi kapatıldığını ayırt etmek için aşağıdaki seçeneklerden birini kullanabilirsiniz:

  • İşleyin WM_SYSCOMMAND, kontrol edin SC_CLOSEve bayrak koyun
  • StackTraceÇerçevelerden herhangi birinin Closeyöntem çağrısı içerip içermediğini kontrol edin .

Örnek 1 - Tanıtıcı 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()");
}

Örnek 2 - StackTrace'i Kontrol Etme

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
Güzel yapılmış. Partiye geç kalmanız çok kötü - eski cevaplarla rekabet etmek zor, zaten yüksek oy alan cevaplar.
mklement0

2
@ mklement0 Umarım gelecekteki kullanıcılar onu faydalı bulacaktır. Cevabı gönderdim çünkü diğer cevabın hiçbiri sorunu doğru bir şekilde çözebilirdi ve bu sayıda görüşe ve yüksek oy alan (çalışmayan) cevaplara sahip bir soru için oldukça garip!
Rıza Aghaei

Çok teşekkürler. Kullandım StackTrace()ve sorunu çözdü.
Ali Majed HA

@AliMajedHA Harika!
Rıza Aghaei

7

Bir formun kapatılması durumunda başvurunun ne zaman kapatılacağını belirler (başvurunuz belirli bir forma eklenmemişse).

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

5

Uygulamalarımda her zaman çıkış Düğmemden alt + x'i yakalayan bir Form Kapatma yöntemi kullanıyorum, alt + f4 veya başka bir form kapatma etkinliği başlatıldı. Tüm sınıflarım, mstrClsTitle = "grmRexcel"bu durumda Özel dize olarak tanımlanan sınıf adına , Form Kapatma Yöntemini ve Form Kapatma Yöntemini çağıran bir Çıkış yöntemine sahiptir. Ayrıca Form Kapatma Yöntemi için bir bildirimim var - this.FormClosing = My Form Closing Form Closing method name.

Bunun kodu:

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;
                }
            }
        }
    }
}


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

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

Kullanıcı form üzerindeki 'X' düğmesini veya kapat düğmesini tıkladığında koşul yürütülürse. Diğer, kullanıcı başka herhangi bir amaçla Alt + f4'ü tıkladığında kullanılabilir


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

DialogResultDaha açık çözüm olarak -Çözüme katılıyorum .

VB.NET yılında ise kalıplaştığı almak için gereklidir 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

Ayrıca formun "InitializeComponent ()" yönteminin içine kapanış işlevini de kaydetmem gerekiyordu:

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

"FormClosing" işlevim verilen yanıta benziyor ( 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");
    }
}

Belirtilmesi gereken bir şey daha var: "FormClosing" sonrasında ortaya çıkan bir "FormClosed" işlevi de vardır. Bu işlevi kullanmak için, aşağıda gösterildiği gibi kaydedin:

this.FormClosed += MainPage_FormClosed;

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

0

Ben bunun gibi bir şey yaptım.

private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if ((sender as Form).ActiveControl is Button)
        {
            //CloseButton
        }
        else
        {
            //The X has been clicked
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.