MessageBoxni muntazam ravishda o'chirishga majbur

Men sizga fonni beray.

Har xil joylarda (yuzlab) MessageBox.Show (....) dan foydalanadigan dastur (o'rta o'lchamli) mavjud.

Ushbu xabarlar qutilari ishlovchilarning bir qismi bo'lib, ular foydalanuvchini ogohlantirish, ogohlantirish yoki kiritish uchun ishlatiladi. Faoliyat bo'lmasa, dastur avtomatik ravishda ma'lum vaqtdan keyin o'chirib qo'yilishi kerak. Biz dasturdan chiqib, sessiya ma'lumotlarini tozalab, fikrlarni tozalash va o'zimizni yashirish uchun faqatgina keyingi ishga tushirilganda vaqt jihatidan qimmatga tushadigan boshlang'ich jarayonni amalga oshirishga majbur bo'lmasligini talab qilamiz.

Har bir narsa yaxshi ishlaydi, lekin ekranda ba'zi xabarlar qutisi mavjud bo'lsa, stsenariyda va foydalanuvchi xabar qutisiga javob bermasdan mashinadan chiqdi, keyin esa dasturni o'chirish uchun hech qanday faoliyat yo'q. Muammo - xabarlar qutisi yo'qolmaydi.

Ilovani yashirishda ochilgan xabar qutisini qanday qilib o'chirib qo'yishim mumkin?

Rahmat.

14
MessageBox.Show (...) modal deb o'yladim, shuning uchun dastur kalitni qanday yuborishi mumkin? Siz mavzu va vazifalarni ishlatasizmi?
qo'shib qo'ydi muallif Fischermaen, manba
Ehtimol, kalitni kiriting yoki esc? :)
qo'shib qo'ydi muallif Reniuz, manba
Javoblaringiz uchun tashakkur. Faqat tayyorlangan msg qutisini foydalanishni aniqlashtirish uchun rework juda katta. ESC kaliti ham to'g'ri emas, chunki faqat faol dastur buyruqni oladi. Id va msg qutisi sarlavhasini bosib, Msgbox moslamasini oladigan FIndWindow yondashuvidan foydalanaman. Ishlov bergandan so'ng, quyidagi win32 API dan foydalanib yopaman: SendMessage (yangi HandleRef (null, msgbxcHandler), WM_CLOSE, IntPtr.Zero, IntPtr.Zero); SendMessage (yangi HandleRef (null, msgbxcHandler), WM_NCDESTROY, IntPtr.Zero, IntPtr.Zero); Hozirgacha uning ishi yaxshi.
qo'shib qo'ydi muallif NYK, manba

9 javoblar

Bu erda UIAutomation (salqin, ammo hali juda ko'p ishlatilmaydigan API) asosida kodning bir qismi ishlatilgan. Joriy jarayonning barcha modal oynalarni (MessageBox bilan ochilganni ham qo'shgan holda) yopish uchun:

    /// 
    /// Attempt to close modal windows if there are any.
    /// 
    public static void CloseModalWindows()
    {
       //get the main window
        AutomationElement root = AutomationElement.FromHandle(Process.GetCurrentProcess().MainWindowHandle);
        if (root == null)
            return;

       //it should implement the Window pattern
        object pattern;
        if (!root.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
            return;

        WindowPattern window = (WindowPattern)pattern;
        if (window.Current.WindowInteractionState != WindowInteractionState.ReadyForUserInteraction)
        {
           //get sub windows
            foreach (AutomationElement element in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)))
            {
               //hmmm... is it really a window?
                if (element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
                {
                   //if it's ready, try to close it
                    WindowPattern childWindow = (WindowPattern)pattern;
                    if (childWindow.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction)
                    {
                        childWindow.Close();
                    }
                }
            }
        }
    }

Misol uchun, ba'zi tugmani bosganingizda MessageBox-ni ochadigan WinForms dasturi mavjud bo'lsa, Windows-ning "Yopish oynasi" menyusidan foydalaning (vazifa satriga o'ng tugmasini bosing) yordamida ilovani yopishingiz mumkin:

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show("Don't click me. I want to be closed automatically!");
    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        const int WM_SYSCOMMAND = 0x0112;
        const int SC_CLOSE = 0xF060;

        if (m.Msg == WM_SYSCOMMAND)//this is sent even if a modal MessageBox is shown
        {
            if ((int)m.WParam == SC_CLOSE)
            {
                CloseModalWindows();
                Close();
            }
        }
        base.WndProc(ref m);
    }

CloseModalWindows-dan kodingizni boshqa joyda qo'llashingiz mumkin, bu faqat namuna.

7
qo'shib qo'ydi
Biroq, .net API-ga murojaat qildim, bu haqda ...
qo'shib qo'ydi muallif Erik Funkenbusch, manba
System.Windows.Automation nom maydoni wpf uchun shunday deydi. msdn.microsoft.com/en-us/library /ms747327(v=vs.110).aspx "Microsoft UI Automation Windows Presentation Foundation (WPF) ni qo'llab-quvvatlovchi barcha operatsion tizimlarida mavjud bo'lgan Microsoft Windows uchun yangi mavjudlik asosidir."
qo'shib qo'ydi muallif Erik Funkenbusch, manba
WPF uchun UIAutomation emasmi? Savol WinForms uchun edi
qo'shib qo'ydi muallif Erik Funkenbusch, manba
@ErikFunkenbusch - wpf uchun nimani anglatishini bilmayman. UIAutomation har qanday dasturni qo'llaydi.
qo'shib qo'ydi muallif Simon Mourier, manba
Ehtimol, lekin UIAutomation wpf bilan cheklangan emas, yoki mijoz sifatida yoki server sifatida. Xuddi shu maqolada ham shunday deyilgan: "WPF tashqari freymlar uchun UI avtomatizatsiya provayderlarini ishlab chiquvchilar."
qo'shib qo'ydi muallif Simon Mourier, manba
Rahmat, menga juda yordam berdi.
qo'shib qo'ydi muallif digitguy, manba

Ushbu bog'laning MSDN forumlarida FindWindow va WM_CLOSE xabarini yuborish orqali xabar qutisini qanday yopish kerakligini ko'rsatadi. Savolga. NET/WindowsCE uchun so'ralgan bo'lsa-da, u sizning muammoingizni echishga olib kelishi mumkin

6
qo'shib qo'ydi
Menimcha, bog'langan sahifaning muammoni qanday hal qila olishi haqida qo'shimcha ma'lumot olish uchun (amalda yalang'och linkni yuborish o'rniga) qo'shimcha amaliyot sifatida qaraladi. Umid qilamanki, qisqa ta'rif berdim, deb o'ylamang. Shunga qaramay, +1 foydali ma'lumotlar manbai bo'lishi mumkin.
qo'shib qo'ydi muallif MartinStettner, manba
Xo'sh, martin, siz mutlaqo haqsiz. vaqt murakkabligi tufayli men ushbu ma'lumotni qo'sha olmadim. ammo tahrirlash uchun rahmat. :)
qo'shib qo'ydi muallif Bravo, manba

Avvalo Savol: Agar xabarlar qutilari ish oqimining bir qismi sifatida ishlatilsa, dastur oqimining o'chirilishiga/davom ettirilishiga yo'l qo'ymaydi.

Sizning uchta variantingiz bor deb o'ylayman

  1. Xabar qutisi klassining o'z versiyasini yarating, unga qo'shimcha vaqt ichida avtomatik ravishda yopilganligi sababli qo'shilgan funksiyali xabar qutisiga o'xshash dialog oynasi ochiladi.

  2. Xabar qutilarini dasturiy tartibda o'chirish uchun C# -ga bu kabi amalni bajaring. http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx

  3. Xabar qutilarini ish oqimini almashtirishdan qutqaring. Bu, ehtimol, eng yaxshi yechim bo'lib, uning ovozidan xabar qutisini yopib turish, dasturiy ta'minotni davom ettirish/o'zgartirishga olib kelishi mumkin va ehtimol hatto boshqa xabarlar qutisiga kerak bo'lmagan bo'lishi mumkinligini ko'rsatishi mumkin. Lekin, ildiz muammosini aniq belgilash, eng yaxshi bo'lishi mumkin, lekin har doim ham oson emas.

1 va 2-alohida ish zarrachalaridan amalga oshirilishi kerak, shuning uchun xabar qutisini blokirovkalashni ko'rsatadigan tarzda uning natijalari haqida o'ylashingiz kerak.

3
qo'shib qo'ydi
3-raqam uchun +1! Men ham, foydalanuvchi buni sezganmi yoki yo'qligini bilmasdan, hech qanday ochiq xabar qutisini "tasdiqlash" hissiyotiga ega emasman ...
qo'shib qo'ydi muallif MartinStettner, manba

SendKeys bilan mening misolim - bu test va ishlaydi:

Bizda fonist va formada tugma borligini aytishimiz mumkin. Tugmani bosganingizdan so'ng - ishchi boshlang va xabar qutisini ko'rsating. DoWork ishchilarida 5 soniya davomida uyquga o'ting va key-messenj qutisini yoping.

private void button1_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
    MessageBox.Show("Close this message!");
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    Thread.Sleep(5000);
    SendKeys.SendWait("{Enter}");//or Esc
}
2
qo'shib qo'ydi
Ushbu hal faqat foydalanuvchi boshqa ilovaga e'tiborni o'zgartirmagan holda ishlaydi. Ilova hali ham diqqat markazida ekanligiga ishonch hosil bo'lolmaysiz. Va Windows dasturni ilova dasturidan boshqa ilovalardan olishiga to'sqinlik qiladi.
qo'shib qo'ydi muallif Alex, manba
Faqat shuni ta'kidlashni istardimki, echim uchun haqiqatan ham xabarlar qutisi ochilganligini tekshirish juda muhim: foydalanuvchi interfeysining istalgan qismiga yuborilgan kirish tugmasi istalmagan oqibatlarga olib kelishi mumkin ...
qo'shib qo'ydi muallif MartinStettner, manba
Ha, sizning fikringiz yaxshi. Uning tezkor ishlash muddati shundan iboratki, kalitni ochish yaxshi emas, escni ishlatish uchun yaxshiroq - UIda bekor qilish kerak.
qo'shib qo'ydi muallif Reniuz, manba

Qo'ng'iroq qilayotgan kodni o'zgartirishingiz mumkin deb taxmin qilish MessageBox.Show() usulini ishlatmaslikni tavsiya qilaman MessageBox. Buning o'rniga, ShowDialog() deb nomlang Bunga asosan MessageBox klassi bilan bir xil ishni bajarish kerak. Keyin siz ariza namunasiga ega bo'lishingiz mumkin va siz bu haqda Close() ga qo'ng'iroq qilishingiz mumkin uni yopish uchun namuna.

Yaxshi misol bu yerda .

1
qo'shib qo'ydi
Ouch. Va odamlarning xabar qutilarini qayta tiklashlari qanchalik dahshatli ekanini ko'p marta ko'rdik. msg sizga haqiqiy xabarlar qutisiga ega bo'lishingiz va kechikishdan keyin uni yopishingiz mumkinligini ko'rsatadi ...
qo'shib qo'ydi muallif Joey, manba
@Joey: ha, sen haqsan ... bu faqat g'oyadir, balki eng yaxshi ehtimol. Siz msg deganingiz haqiqiy xabarlar qutisiga ega bo'lishingiz va kechikishdan keyin uni yopishingiz mumkinligini ko'rsatadi ... ... nima va kim "msg"? Kechirasiz, tushunmayapman, afv etasiz
qo'shib qo'ydi muallif Marco, manba

O'ylaymanki, siz eng yaxshi yo'l sizni o'zingizning xabarlar qutisi shaklini amalga oshirishdir

class MyMessageBox : Form {
  private MyMessageBox currentForm;//The currently active message box

  public static Show(....) {//same as MessageBox.Show
   //...
  }

  public static Show(...) {//define additional overloads
  }

  public static CloseCurrent() {
    if (currentForm != null)
      currentForm.Close();
  }

 //...
}

Ba'zi katta loyihalarimda men ushbu yondashuvni boshqa maqsadlar uchun foydali deb topdim (masalan, xato xabarlarini avtomatik yozish va boshqalar)

GetTopWindow() (yoki boshqa WIN32 funksiyasi) dasturidan foydalanadigan joriy yuqori darajadagi oynani olish va WM_CLOSE xabarini yuborish uchun foydalanadigan ikkinchi fikrim unga.

1
qo'shib qo'ydi
foydalanuvchining kerakli xabar qutisi ustida ko'rsatilgan pastki yorlig'i yoki boshqa xabar qutisi bo'lsa nima bo'ladi. Bu stsenariyda, men u istalmaganni yopib qo'yishini taxmin qilaman.
qo'shib qo'ydi muallif Vivekh, manba

Refer to DmitryG post in "Close a MessageBox after several seconds"

Vaqt tugashi bilanoq MessageBox-ni avtomatik yopish

using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

    public class AutoClosingMessageBox
    {
        System.Threading.Timer _timeoutTimer;
        string _caption;
        AutoClosingMessageBox(string text, string caption, int timeout)
        {
            _caption = caption;
            _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
                null, timeout, System.Threading.Timeout.Infinite);
            MessageBox.Show(text, caption);
        }
        public static void Show(string text, string caption, int timeout)
        {
            new AutoClosingMessageBox(text, caption, timeout);
        }
        void OnTimerElapsed(object state)
        {
            IntPtr mbWnd = FindWindow(null, _caption);
            if (mbWnd != IntPtr.Zero)
                SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            _timeoutTimer.Dispose();
        }
        const int WM_CLOSE = 0x0010;
        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    }

va uni qo'ng'iroq qiling

AutoClosingMessageBox.Show("Content", "Title", TimeOut);
1
qo'shib qo'ydi

Men foydalanar .net 2 va ikkita yondashuv xuddi shu hiyla bilan.

Open the MessageBox from stub-Form with MessageBox.Show(this,"message")

Shakl ko'rinmasa yoki, albatta, foydalanuvchi interfeysi mavjud emas.

  1. Keep the form handler and close it with:

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    

    or

  2. holding the form as class parameter and using FormX.Close().

Shakl, MessageBox-ning egasi bo'lgani uchun, uni yopish MessageBoxni yopadi.

1
qo'shib qo'ydi

Buning uchun o'zingizning nazoratingizni qiling va u yerda bo'lishni xohlagan xatti-harakatlaringizni amalga oshiring. Bir variant sifatida, bu MessageBoxni yopish uchun taymer bo'lishi mumkin.

0
qo'shib qo'ydi