MessageBox бағдарламасын жүйелі түрде жабу керек

Сізге фонды беремін.

Біз әр түрлі орындарда (жүздеген) MessageBox.Show (....) қолданатын бағдарлама (орташа өлшемді) бар.

Бұл хабарламалар жәшіктері жұмыс элементінің бөлігі болып табылады және пайдаланушыны хабардар ету, ескерту немесе енгізу үшін пайдаланылады. Әрекет жоқ болса, белгілі бір уақыттан кейін автоматты түрде тіркелу қажет. Бізде сеанстық деректерді тазарту, көріністерді тазалау және жасыру үшін жасырынып, уақытты қымбат тұратын іске қосу процесін орындау қажет емес екендігін талап ету қажет.

Барлығы жақсы жұмыс істейді, бірақ экранда кейбір хабар терезесі болғанда және пайдаланушы хабарларды терезесіне жауап бермей машинаны тастағаннан кейін бағдарламаны өшіріп тастау үшін ешқандай әрекетсіздіктен жұмыс істейді. Мәселе - хабарлама жолағы жоғалып кетпейді.

Қолданбаны жасырып жатқанда ашылған хабарларды қалай жабуға болады?

Рахмет.

14
MessageBox.Show (...) деп ойладым, сондықтан бағдарлама кілтін қалай жібере алады? Жиектерді/тапсырмаларды пайдаланасыз ба?
қосылды автор Fischermaen, көзі
Кілт енгізу немесе esc жібере аласыз ба? :)
қосылды автор Reniuz, көзі
Жауаптарыңызға рақмет. Тек баптандырылған msg терезесін пайдалануды түсіндіру үшін опция емес, себебі қайта құру өте үлкен. ESC кілтін жіберу дұрыс емес, себебі тек белсенді бағдарлама пәрменді алады. Менде FIndWindow әдісін қолданамын, мұнда Msgbox идентификаторын идентификатор және msg ұяшығының атын өту арқылы аламын. Ұстаушыны алғаннан кейін келесі win32 API, мысалы: SendMessage (жаңа HandleRef (null, msgbxcHandler), WM_CLOSE, IntPtr.Zero, IntPtr.Zero); SendMessage (жаңа HandleRef (null, msgbxcHandler), WM_NCDESTROY, IntPtr.Zero, IntPtr.Zero); Әзірше оның жақсы жұмыс істеуі.
қосылды автор NYK, көзі

9 жауаптар

Мұнда UIAutomation (салқын, бірақ әлі де өте пайдаланылмаған API) негізінде жасалған код бөлігі ағымдағы үрдістің барлық модальды терезелерін (оның ішінде MessageBox арқылы ашылған) жабу үшін:

    /// 
/// 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();
                    }
                }
            }
        }
    }

Мысалы, кейбір түймешіктерді басқан кезде MessageBox терезесін шығаратын WinForms бағдарламасы болса, Windows жүйесін «Терезені жабу» мәзірін қолданып (тапсырмалар жолында тінтуірдің оң жақ түймешігімен басу арқылы) бағдарламаны жаба аласыз:

    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-ны сіздің кодыңызда басқа жерде қолдануға болады, бұл жай ғана үлгі.

7
қосылды
Мен, алайда, .net API-ға сілтеме жасай алдым, ол туралы ...
қосылды автор Erik Funkenbusch, көзі
WPF үшін UIAтомациясы емес пе? Сұрақ WinForms үшін болды
қосылды автор Erik Funkenbusch, көзі
@ErikFunkenbusch - «WPF үшін» дегеніміз не екенін білмеймін. UIAutomation кез-келген қосымшаны қолдайды.
қосылды автор Simon Mourier, көзі
Мүмкін, бірақ UIAтомациясы WPF-мен ғана емес, сонымен қатар клиент ретінде немесе сервер ретінде. Сол мақалада сондай-ақ: «WPF-тен басқа UI автоматтандыру провайдерлерінің әзірлеушілері.»
қосылды автор Simon Mourier, көзі
Рахмет, маған көп көмектесті.
қосылды автор digitguy, көзі

Бұл сілтеме MSDN форумдарында FindWindow және WM_CLOSE хабарламасын жіберу арқылы хабарламаның терезесін қалай жабу керектігі көрсетілген. Сұрақ туындаған кезде .NET/WindowsCE сұралған, ол сіздің мәселеңізді шешуі мүмкін

6
қосылды
Менің ойымша, кем дегенде, байланыстырылған беттің мәселені қалай шеше алатыны туралы қосымша ақпараттарды қосудың жақсы тәжірибесі деп есептеймін (тек қана жалған сілтеме жасаудың орнына). Мен қысқаша сипаттаманы қосқаныма қарсы емес деп үміттенемін. +1 бәрібір пайдалы ресурс болуы мүмкін.
қосылды автор MartinStettner, көзі
Ал Мартин, сен мүлде дұрыс. Уақыттың күрделілігіне байланысты мен бұл ақпаратты қоса алмадым. бірақ редакциялауға рахмет. :)
қосылды автор Bravo, көзі

Алғашқы сұрақ: Егер хабарлар жәшіктері жұмыс үрдісінің бөлігі ретінде пайдаланылса, бағдарлама жолында бағдарлама жолында ағымның өзгеруі/жалғастыруына себеп бола ма?

Менің ойымша, сізде үш нұсқасы бар

  1. Уақыт өткеннен кейін автоматты түрде жабылған функциясымен қосылған пошта жәшігіне ұқсайтын тілқатысу терезесін ашатын хабарлар жәшігі класының өзіңіздің нұсқаңызды жасаңыз.

  2. Хабарламалар терезелерін жүйелі түрде жабу үшін C# -де осындай нәрсе орындаңыз. http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx

  3. Хабарламалар жолақтарын жұмыс үрдісін бұзудан құтқарыңыз. Бұл, ең алдымен, дыбыстық сигналды бағдарламалық жасақтаманы жабудағы үздік шешім, жұмыс процесінің жалғасуына/өзгеруіне әкеп соғуы мүмкін және, мүмкін, тағы бір хабар терезесінің пайда болуы мүмкін болмауы мүмкін. Бірақ, ең бастысы, тамыр проблемасын шешу жақсы болуы мүмкін, бірақ әрдайым оңай емес.

1 және 2-бөлек жекелеген жіптен жасалуы керек, сондықтан сіз оның салдары туралы ойлауыңыз керек, өйткені хабарларды сақтау блогы бұғатталады.

3
қосылды
3-тармақ үшін +1! Мен сондай-ақ, егер пайдаланушы оны байқаған-болмайтынын білмесеңіз, кез-келген ашық хат-хабар терезесін «растау» туралы жақсы сезім болмас еді ...
қосылды автор MartinStettner, көзі

SendKeys көмегімен менің мысал - сыналған және жұмыс істейді:

бізде формада жұмысшы және пішіндегі батырма бар деп айтуға болады. Түймешік басылғаннан кейін - жұмысшыны бастаңыз және хабарлама жолағын көрсетіңіз. DoWork жұмысшыларында 5с ұйқыға ұйқы, содан кейін пернетақтадағы кілтсөзді жауып қойыңыз.

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
қосылды
Бұл шешім тек фокусты басқа қолданбаға өзгертпесе ғана жұмыс жасайды. Қолданба әлі де фокус бар екеніне сенімді болмайсыз. Сондай-ақ, Windows бағдарламасы бағдарламаны басқа бағдарламадан фокустауды болдырмайды.
қосылды автор Alex, көзі
Мен жай ғана шешім қабылдау үшін шынымен хабарламаның терезесін ашатындығын атап өтуді қалаймын: пайдаланушы интерфейсінің кез келген басқа бөлігіне жіберілген кілт сөзсіз салдарға әкелуі мүмкін ...
қосылды автор MartinStettner, көзі
Иә, сіздің ойыңыз жақсы. Оның жылдам әрекет етуі кілтті енгізеді, анық, кілт емес, esc-ды пайдалану үшін жақсы - UI-де ол бас тартуды білдіреді.
қосылды автор Reniuz, көзі

Сіз қоңырау шалып жатқан кодты редакциялауға рұқсат ретінде қабылдайсыз MessageBox.Show() әдісін пайдаланбаймын MessageBox. Оның орнына ShowDialog() деп аталатын өзіңіздің реттелетін пішінді пайдаланыңыз ол негізінен MessageBox сыныбымен бірдей нәрсе істеу керек. Сосың сен пішіннің өзі данасы бар және сіз оны Close() деп атауға болады мысалы, оны жабу үшін.

Жақсы мысал мұнда .

1
қосылды
Ouch. Адамдар хабарларды жәшіктерін қайтадан жасағанда, біз қаншалықты қорқынышты екенін бірнеше рет көреміз. msg дегеніміз нақты хабар терезесіне ие болуға және кешігуден кейін оны жауып қоюға болатындығын көрсетеді ...
қосылды автор Joey, көзі
@Joey: иә, сіз дұрыссыз ... бұл идея ғана емес, жақсы. Сіз msg деп айтатын болсаңыз, сіз нақты хабар терезесіне ие боласыз және кешіктіргеннен кейін оны жауып тастаңыз ... не «msg» деген не? Кешіріңіз, түсінбеймін, кешірім сұраймын
қосылды автор Marco, көзі

Менің ойымша, ең таза әдіс сізді өзіңіздің хабарламаңыздың қорапшасының нысанын іске асырады

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

 //...
}

Кейбір үлкен жобаларым бойынша, мен бұл тәсілді басқа мақсаттарға пайдалы деп таптым (мысалы, қате туралы хабарларды автоматты түрде тіркеу және т.б.)

Қолданбаның ағымдағы жоғарғы деңгейлі терезесін алу үшін GetTopWindow() (немесе кейбір басқа WIN32 функциясы) қолданып, WM_CLOSE хабарламасын жіберу үшін қолданатын екінші идея оған.

1
қосылды
егер пайдаланушы пайдаланушы тілқатысу терезесін немесе басқа хабарламаның терезесін қалаған хабарламаның терезесінің үстінде көрсетсе не істей алады? Бұл сценарийде ол қалаусызды жабады деп ойлаймын.
қосылды автор Vivekh, көзі

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

Күту уақыты аяқталғаннан кейін MessageBox-ты авто-жабу

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

және оны арқылы қоңырау шалыңыз

AutoClosingMessageBox.Show("Content", "Title", TimeOut);
1
қосылды

Мен 2-ші желіні қолдандым, сол сияқты екі әдісті қолдандым.

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

Пішін көрінбесе немесе шынымен UI болмаса.

  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().

Пішін MessageBox иесі болғандықтан, оны жабу MessageBox жабылады.

1
қосылды

Бұл үшін өзіңіздің жеке бақылауыңызды жасаңыз және сізде болуы керек мінез-құлықты іске асырыңыз. Опция ретінде бұл MessageBox жабу үшін таймер болуы мүмкін.

0
қосылды