कई सेकंड के बाद एक संदेश बॉक्स बंद करें


82

मेरे पास एक Windows फ़ॉर्म अनुप्रयोग VS2010 C # है जहां मैं एक संदेश दिखाने के लिए एक संदेश बॉक्स प्रदर्शित करता हूं।

मेरे पास एक ठीक बटन है, लेकिन यदि वे चले जाते हैं, तो मैं 5 सेकंड कहने के बाद संदेश बॉक्स को टाइमआउट और बंद करना चाहता हूं, स्वचालित रूप से संदेश बॉक्स बंद कर देता हूं।

कस्टम संदेशबॉक्स (जो फ़ॉर्म से विरासत में मिला है) या किसी अन्य रिपोर्टर फ़ॉर्म हैं, लेकिन यह दिलचस्प होगा कि फ़ॉर्म आवश्यक नहीं है।

इसके बारे में कोई सुझाव या नमूने?

अपडेट किया गया:

WPF के लिए
C # में स्वचालित रूप से संदेश बॉक्स बंद करें

कस्टम संदेशबॉक्स (फ़ॉर्म इनहेरिट का उपयोग करके)
http://www.codeproject.com/Articles/17253/A-Custom-Message-Box

http://www.codeproject.com/Articles/327212/Custom-Message-Box-in-VC

http://tutplusplus.blogspot.com.es/2010/07/c-tutorial-create-your-own:cb.html

http://medmondson2011.wordpress.com/2010/04/07/easy-to-use-custom-c-message-box-with-a-configurable-checkbox/

स्क्रॉल करने योग्य मैसेजबॉक्स
C # में एक स्क्रॉल करने योग्य मैसेजबॉक्स

अपवाद रिपोर्टर
/programming/49224/good-crash-reporting-library-in-c-sharp

http://www.codeproject.com/Articles/6895/A-Reusable-Flexible-Error-Reporting-Framework

उपाय:

शायद मुझे लगता है कि निम्नलिखित उत्तर अच्छे समाधान हैं, बिना फॉर्म का उपयोग किए।

https://stackoverflow.com/a/14522902/206730
https://stackoverflow.com/a/14522952/206730


1
इस पर एक नज़र डालें (विंडोज़ फोन, लेकिन समान होना चाहिए): stackoverflow.com/questions/9674122/…
jAC

6
@istepaniuk वह कोशिश नहीं कर सकता अगर वह नहीं जानता। इसलिए इस तरह के सवालों को बंद करो
मुस्तफा एकीस

1
आपको एक टाइमर बनाने में सक्षम होना चाहिए और इसे निर्धारित समय के बाद बंद करने के लिए सेट करना चाहिए
स्टीवन एकले

2
आप फॉर्म को एकMessageBox
स्पैज

2
@MustafaEkici, मैं ओपी को यह दिखाने के लिए आमंत्रित कर रहा था कि उसने क्या कोशिश की है। मुझे लगता है कि उसने एसओ में वास्तव में पूछने से पहले कोशिश की और असफल रहा होगा। इसलिए रामहाउंड और मैंने इस सवाल को खारिज कर दिया। आप meta.stackexchange.com/questions/122986/…
istepaniuk

जवाबों:


123

निम्नलिखित दृष्टिकोण का प्रयास करें:

AutoClosingMessageBox.Show("Text", "Caption", 1000);

जहां AutoClosingMessageBoxकक्षा निम्नलिखित के रूप में लागू की गई है:

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);
        using(_timeoutTimer)
            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("#32770", _caption); // lpClassName is #32770 for MessageBox
        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);
}

अद्यतन: यदि आप अंतर्निहित मैसेजबॉक्स का रिटर्न वैल्यू प्राप्त करना चाहते हैं जब उपयोगकर्ता टाइमआउट से पहले कुछ का चयन करता है तो आप इस कोड के निम्नलिखित संस्करण का उपयोग कर सकते हैं:

var userResult = AutoClosingMessageBox.Show("Yes or No?", "Caption", 1000, MessageBoxButtons.YesNo);
if(userResult == System.Windows.Forms.DialogResult.Yes) { 
    // do something
}
...
public class AutoClosingMessageBox {
    System.Threading.Timer _timeoutTimer;
    string _caption;
    DialogResult _result;
    DialogResult _timerResult;
    AutoClosingMessageBox(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) {
        _caption = caption;
        _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
            null, timeout, System.Threading.Timeout.Infinite);
        _timerResult = timerResult;
        using(_timeoutTimer)
            _result = MessageBox.Show(text, caption, buttons);
    }
    public static DialogResult Show(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) {
        return new AutoClosingMessageBox(text, caption, timeout, buttons, timerResult)._result;
    }
    void OnTimerElapsed(object state) {
        IntPtr mbWnd = FindWindow("#32770", _caption); // lpClassName is #32770 for MessageBox
        if(mbWnd != IntPtr.Zero)
            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        _timeoutTimer.Dispose();
        _result = _timerResult;
    }
    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);
}

फिर भी एक और अद्यतन

मैंने YesNoबटन के साथ @ जैक के मामले की जांच की है और पाया है कि WM_CLOSEसंदेश भेजने के साथ दृष्टिकोण बिल्कुल भी काम नहीं करता है।
मैं अलग आटोक्लासिंगमेसेज़बॉक्स लाइब्रेरी के संदर्भ में एक फिक्स प्रदान करूंगा । इस लाइब्रेरी में पुन: डिज़ाइन किया गया दृष्टिकोण है और मेरा मानना ​​है कि किसी के लिए उपयोगी हो सकता है।
यह NuGet पैकेज के माध्यम से भी उपलब्ध है :

Install-Package AutoClosingMessageBox

रिलीज़ नोट्स (v1.0.0.2):
- नए शो (IWin32Owner) एपीआई सबसे लोकप्रिय परिदृश्यों का समर्थन करने के लिए ( # 1 के संदर्भ में );
- नई फैक्टरी () एपीआई मैसेजबॉक्स दिखाने पर पूर्ण नियंत्रण प्रदान करने के लिए;


बेहतर उपयोग System.Threading.Timer या System.Timers.Timer (जैसे @ उत्तर)? SendMessage बनाम PostMessage?
किनिकेत

@Kiquenet मेरा मानना ​​है कि इस विशिष्ट स्थिति में कोई महत्वपूर्ण अंतर नहीं हैं।
दिमित्रीग

1
@GeorgeBirbilis धन्यवाद, यह समझ में आ सकता है ... इस मामले में आप #32770एक वर्ग के नाम के रूप में मूल्य का उपयोग कर सकते हैं
दिमित्री

2
यह मेरे लिए काम नहीं करता है अगर बटन हैंSystem.Windows.Forms.MessageBoxButtons.YesNo
जैक

1
@Jack देर से जवाब के लिए क्षमा करें, मैंने YesNoबटन के साथ मामले की जांच की है - आप बिल्कुल सही हैं - यह काम नहीं करता है। मैं अलग AutoclosingMessageBox लाइब्रेरी के संदर्भ में एक फिक्स प्रदान करेगा । पुनर्निर्देशित दृष्टिकोण शामिल है और, मेरा मानना ​​है कि उपयोगी हो सकता है। धन्यवाद!
दिमित्रीग

32

एक समाधान जो WinForms में काम करता है:

var w = new Form() { Size = new Size(0, 0) };
Task.Delay(TimeSpan.FromSeconds(10))
    .ContinueWith((t) => w.Close(), TaskScheduler.FromCurrentSynchronizationContext());

MessageBox.Show(w, message, caption);

संदेश बॉक्स के मालिक के रूप को बंद करने के प्रभाव के आधार पर बॉक्स को भी बंद कर दिया जाएगा।

Windows प्रपत्र नियंत्रण की आवश्यकता है कि उन्हें उसी थ्रेड पर एक्सेस किया जाना चाहिए जिसने उन्हें बनाया था। उपयोग करने TaskScheduler.FromCurrentSynchronizationContext()से यह सुनिश्चित होगा कि, ऊपर दिया गया उदाहरण कोड UI थ्रेड या उपयोगकर्ता द्वारा निर्मित थ्रेड पर निष्पादित किया जाता है। यदि कोड थ्रेड पूल (जैसे टाइमर कॉलबैक) या कार्य पूल (जैसे डिफ़ॉल्ट पैरामीटर के साथ TaskFactory.StartNewया बनाए गए कार्य पर) से एक थ्रेड पर निष्पादित किया जाता है, तो उदाहरण सही ढंग से काम नहीं करेगा Task.Run


संस्करण .NET क्या है? यह क्या है कार्यपालक?
किकेनेट

1
@Kiquenet .NET 4.0 और ऊपर। Taskऔर mscorlib.dll में TaskSchedulerनाम स्थान से हैं, System.Threading.Tasksइसलिए किसी अतिरिक्त विधानसभा संदर्भ की आवश्यकता नहीं है।
बीएसएचआरपी

महान समाधान! एक जोड़ ... यह एक Winforms ऐप में अच्छी तरह से काम करता है, इसे बनाने के ठीक बाद नए रूप के लिए लाया जाने वाला AddToFront जोड़ रहा है। अन्यथा, संवाद बॉक्स कभी-कभी वर्तमान सक्रिय रूप के पीछे दिखाया जाता है, अर्थात, उपयोगकर्ता को दिखाई नहीं देता। var w = new Form () {आकार = नया आकार (0, 0)}; w.BringToFront ();
डेवलपर

@ डेवलपर 63 मैं आपके अनुभव को पुन: पेश नहीं कर सका। w.SentToBack()ठीक पहले कॉल करते समय MessageBox.Show(), संवाद बॉक्स अभी भी मुख्य रूप के शीर्ष पर दिखाया गया था। .NET 4.5 और 4.7.1 पर परीक्षण किया गया।
बीएसएचआर

यह समाधान अच्छा हो सकता है, लेकिन यह केवल .NET 4.5 और ऊपर से उपलब्ध है, 4.0 नहीं (टास्क.डेल के कारण) देखें: stackoverflow.com/questions/17717047/…
KwentRell

16

AppActivate!

यदि आप अपने संदर्भों को थोड़ा गुनगुनाने से गुरेज नहीं करते हैं, तो आप शामिल कर सकते हैं Microsoft.Visualbasic, इसे बहुत ही कम तरीके से और उपयोग ।

संदेश बॉक्स प्रदर्शित करें

    (new System.Threading.Thread(CloseIt)).Start();
    MessageBox.Show("HI");

बंद करें

public void CloseIt()
{
    System.Threading.Thread.Sleep(2000);
    Microsoft.VisualBasic.Interaction.AppActivate( 
         System.Diagnostics.Process.GetCurrentProcess().Id);
    System.Windows.Forms.SendKeys.SendWait(" ");
}

अब अपने हाथ धो लो!


11

System.Windows.MessageBox.Show () विधि में एक अधिभार है जो पहले पैरामीटर के रूप में एक मालिक विंडो लेता है। यदि हम एक अदृश्य स्वामी विंडो बनाते हैं, जिसे हम निर्दिष्ट समय के बाद बंद कर देते हैं, तो यह बाल संदेश बॉक्स के साथ ही बंद हो जाएगा।

Window owner = CreateAutoCloseWindow(dialogTimeout);
MessageBoxResult result = MessageBox.Show(owner, ...

अब तक सब ठीक है। लेकिन हम एक विंडो को कैसे बंद कर सकते हैं अगर यूआई थ्रेड संदेश बॉक्स द्वारा अवरुद्ध है और यूआई नियंत्रण एक कार्यकर्ता थ्रेड से एक्सेस नहीं किया जा सकता है? इसका उत्तर है - स्वामी विंडो हैंडल पर WM_CLOSE विंडो संदेश भेजकर:

Window CreateAutoCloseWindow(TimeSpan timeout)
{
    Window window = new Window()
    {
        WindowStyle = WindowStyle.None,
        WindowState = System.Windows.WindowState.Maximized,
        Background =  System.Windows.Media.Brushes.Transparent, 
        AllowsTransparency = true,
        ShowInTaskbar = false,
        ShowActivated = true,
        Topmost = true
    };

    window.Show();

    IntPtr handle = new WindowInteropHelper(window).Handle;

    Task.Delay((int)timeout.TotalMilliseconds).ContinueWith(
        t => NativeMethods.SendMessage(handle, 0x10 /*WM_CLOSE*/, IntPtr.Zero, IntPtr.Zero));

    return window;
}

और यहाँ SendMessage Windows API विधि के लिए आयात है:

static class NativeMethods
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}

विंडो का प्रकार विंडोज फॉर्म के लिए है?
किवनीत

आपको इसे बंद करने के लिए छिपी हुई मूल विंडो पर संदेश भेजने की आवश्यकता क्यों है? क्या आप इस पर कुछ "क्लोज़" विधि नहीं कह सकते हैं या इसे दूसरे तरीके से डिस्पोज़ कर सकते हैं?
जॉर्ज बीरबिलिस

मेरे खुद के सवाल का जवाब देने के लिए, उस WPF विंडो की स्वामित्व वाली संपत्ति 0 विंडो दिखाती है और बंद संदेश
बॉक्स

2
ब्रिलियंट समाधान। इसमें कुछ नामकरण ओवरलैप है System.Windowsऔर System.Windows.Formsमुझे यह पता लगाने में कुछ समय लगा। : आप निम्नलिखित की आवश्यकता होगी System, System.Runtime.InteropServices, System.Threading.Tasks, System.Windows, System.Windows.Interop,System.Windows.Media
m3tikn0b

10

आप यह कोशिश कर सकते हैं:

[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

[DllImport("user32.Dll")]
static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);

private const UInt32 WM_CLOSE = 0x0010;

public void ShowAutoClosingMessageBox(string message, string caption)
{
    var timer = new System.Timers.Timer(5000) { AutoReset = false };
    timer.Elapsed += delegate
    {
        IntPtr hWnd = FindWindowByCaption(IntPtr.Zero, caption);
        if (hWnd.ToInt32() != 0) PostMessage(hWnd, WM_CLOSE, 0, 0);
    };
    timer.Enabled = true;
    MessageBox.Show(message, caption);
}

2
बेहतर उपयोग System.Threading.Timer या System.Timers.Timer (@DmitryG उत्तर की तरह)? SendMessage बनाम PostMessage?
कीकेनेट

1
SendMessage और PostMessage के बीच अंतर पर stackoverflow.com/questions/3376619/… और शायद stackoverflow.com/questions/2411116/… भी देखें
जॉर्ज बिर्बिलिस

7

कोडप्रोजेक्ट के ऊपर रोजरबी के पास इस जवाब का सबसे पतला समाधान है, और उसने '04 में वापस किया, और यह अभी भी धमाकेदार है '

मूल रूप से, आप यहां उसकी परियोजना में जाते हैं और सीएस फ़ाइल डाउनलोड करते हैं । अगर उस लिंक की कभी मृत्यु हो जाती है, तो मुझे यहां बैकअप जिप मिल गया है। अपने प्रोजेक्ट में CS फ़ाइल जोड़ें, या यदि आप ऐसा करेंगे तो कोड को कहीं पर कॉपी / पेस्ट करें।

फिर, आपको बस इतना करना है

DialogResult result = MessageBox.Show("Text","Title", MessageBoxButtons.CHOICE)

सेवा

DialogResult result = MessageBoxEx.Show("Text","Title", MessageBoxButtons.CHOICE, timer_ms)

और आप जाने के लिए अच्छे हैं।


2
मुझे एक त्वरित समाधान की आवश्यकता थी और इसने बहुत काम किया! साझा करने के लिए धन्यवाद।
मार्क क्रैम

1
आप अपने उदाहरणों में .Show एक्सटेंशन से चूक गए ... पढ़ना चाहिए: DialogResult result = MessageBoxEx.Show ("टेक्स्ट", "शीर्षक", MessageBoxButtons.CHOICE, टाइमर_ms)
Edd

2

वहाँ एक codeproject परियोजना उपलब्ध है यहाँ है कि इस functuanility प्रदान करता है।

एसओ और अन्य बोर्डों पर यहां कई थ्रेड्स के बाद इस कैंट को सामान्य मैसेजबॉक्स के साथ किया जा सकता है।

संपादित करें:

मेरे पास एक विचार है जो थोड़ा सा अहम् है ..

मैसेजबॉक्स दिखाई देने पर टाइमर का उपयोग करें और शुरू करें। यदि आपका मैसेजबॉक्स केवल ओके बटन (केवल 1 संभावना) सुनता है, तो ईएससी-प्रेस का अनुकरण करने SendKeys.Send("{ESC}");और फिर टाइमर को बंद करने के लिए ऑन-इवेंट का उपयोग करें ।


1
टाइमर की अवधारणा एक सरल तरीका है ... लेकिन यह सुनिश्चित करने के लिए भेजे गए कुंजियों को अपने ऐप को हिट करना है कि क्या यह फोकस नहीं करता है या खो देता है। इसके लिए SetForegroundWindow की आवश्यकता होगी और उत्तर में अधिक कोड शामिल करने के लिए शुरू होता है, लेकिन नीचे 'AppActivate' देखें।
FastAl

2

DMitryG के कोड "अंतर्निहित का रिटर्न वैल्यू प्राप्त करें MessageBox" में एक बग है इसलिए टाइमरResult वास्तव में कभी भी सही ढंग से वापस नहीं आया है ( MessageBox.Showकॉल वापस OnTimerElapsedपूरा होने पर)। मेरा फिक्स नीचे है:

public class TimedMessageBox {
    System.Threading.Timer _timeoutTimer;
    string _caption;
    DialogResult _result;
    DialogResult _timerResult;
    bool timedOut = false;

    TimedMessageBox(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None)
    {
        _caption = caption;
        _timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
            null, timeout, System.Threading.Timeout.Infinite);
        _timerResult = timerResult;
        using(_timeoutTimer)
            _result = MessageBox.Show(text, caption, buttons);
        if (timedOut) _result = _timerResult;
    }

    public static DialogResult Show(string text, string caption, int timeout, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult timerResult = DialogResult.None) {
        return new TimedMessageBox(text, caption, timeout, buttons, timerResult)._result;
    }

    void OnTimerElapsed(object state) {
        IntPtr mbWnd = FindWindow("#32770", _caption); // lpClassName is #32770 for MessageBox
        if(mbWnd != IntPtr.Zero)
            SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        _timeoutTimer.Dispose();
        timedOut = true;
    }

    const int WM_CLOSE = 0x0010;
    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    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);
}

1

Vb.net लाइब्रेरी में इसके लिए इंटरैक्शन क्लास का उपयोग करके एक सरल समाधान है:

void MsgPopup(string text, string title, int secs = 3)
{
    dynamic intr = Microsoft.VisualBasic.Interaction.CreateObject("WScript.Shell");
    intr.Popup(text, secs, title);
}

bool MsgPopupYesNo(string text, string title, int secs = 3)
{
    dynamic intr = Microsoft.VisualBasic.Interaction.CreateObject("WScript.Shell");
    int answer = intr.Popup(text, secs, title, (int)Microsoft.VisualBasic.Constants.vbYesNo + (int)Microsoft.VisualBasic.Constants.vbQuestion);
    return (answer == 6);
}

0

Message32Timeout () नाम के user32.dll में एक अनिर्दिष्ट एपीआई है, लेकिन इसके लिए Windows XP या बाद के संस्करण की आवश्यकता होती है।


0

EndDialogभेजने के बजाय उपयोग करें WM_CLOSE:

[DllImport("user32.dll")]
public static extern int EndDialog(IntPtr hDlg, IntPtr nResult);

0

मैंने इसे इस तरह किया

var owner = new Form { TopMost = true };
Task.Delay(30000).ContinueWith(t => {
owner.Invoke(new Action(()=>
{
      if (!owner.IsDisposed)
      {
          owner.Close();
      }
   }));
});
var dialogRes =  MessageBox.Show(owner, msg, "Info", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.