visual personalizado net ejemplos como close cerrar automaticamente automatically c# winforms messagebox

personalizado - messagebox temporal c#



Cierre un MessageBox después de varios segundos (9)

Tengo una aplicación Windows Forms VS2010 C # donde visualizo un MessageBox para mostrar un mensaje.

Tengo un botón de autorización, pero si se retiran, quiero esperar y cerrar el cuadro de mensaje después de, digamos, 5 segundos, cerrar automáticamente el cuadro de mensaje.

Hay un MessageBox personalizado (heredado de Form) u otro Form reporter, pero sería interesante no necesariamente un Formulario.

Alguna sugerencia o muestras al respecto?

Actualizado:

Para WPF
Cerrar automáticamente el cuadro de mensaje en C #

Custom MessageBox (usando Form hereder)
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-custom.html

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

Scrolllable MessageBox
Un cuadro de mensaje desplazable en C #

Reportero de excepción
https://stackoverflow.com/questions/49224/good-crash-reporting-library-in-c-sharp

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

Solución:

Tal vez creo que las siguientes respuestas son una buena solución, sin usar un Formulario.

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


AppActivate!

Si no le molesta enredar un poco sus referencias, puede incluir Microsoft.Visualbasic, y usar esta manera muy breve.

Mostrar el MessageBox

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

Función CloseIt:

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

¡Ahora vete a lavarte las manos!


El código de DMitryG "obtener el valor de retorno del MessageBox subyacente" tiene un error por lo que el timerResult nunca se devuelve correctamente ( MessageBox.Show devuelve la llamada DESPUÉS de que OnTimerElapsed complete). Mi solución está a continuación:

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


El método System.Windows.MessageBox.Show () tiene una sobrecarga que toma una ventana de propietario como primer parámetro. Si creamos una ventana de propietario invisible que luego cerramos después de un tiempo específico, también se cerrará el cuadro de mensaje secundario.

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

Hasta aquí todo bien. Pero, ¿cómo cerramos una ventana si el hilo de la interfaz de usuario está bloqueado por el cuadro de mensaje y no se puede acceder a los controles de la interfaz de usuario desde un hilo de trabajo? La respuesta es - al enviar un mensaje de Windows WM_CLOSE al manejador de la ventana del propietario:

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

Y aquí está la importación para el método 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); }


Hay un proyecto de proyecto de código disponible HERE que proporciona esta función.

Después de muchos hilos aquí en SO y otras placas, esto no se puede hacer con el MessageBox normal.

Editar:

Tengo una idea que es un poco ehmmm, sí ...

Use un temporizador y comience cuando aparezca MessageBox. Si su MessageBox solo escucha el botón OK (solo 1 posibilidad), entonces use OnTick-Event para emular un ESC-Press con SendKeys.Send("{ESC}"); y luego detén el temporizador.


Hay una API no documentada en user32.dll llamada MessageBoxTimeout () pero requiere Windows XP o posterior.


Pruebe el siguiente enfoque:

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

Donde la clase AutoClosingMessageBox implementó de la siguiente manera:

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

Actualización: si desea obtener el valor de retorno del MessageBox subyacente cuando el usuario selecciona algo antes del tiempo de espera, puede usar la siguiente versión de este código:

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

Aún otra actualización

YesNo el caso de YesNo con los botones YesNo y descubrí que el enfoque con el envío del mensaje WM_CLOSE no funciona en absoluto.
Proporcionaré una solución en el contexto de la biblioteca separada AutoclosingMessageBox . Esta biblioteca contiene un enfoque rediseñado y, creo, puede ser útil para alguien.
También disponible a través del paquete NuGet :

Install-Package AutoClosingMessageBox

Notas de la versión (v1.0.0.2):
- Nueva API Show (IWin32Owner) para admitir los escenarios más populares (en el contexto de #1 );
- API New Factory () para proporcionar control total en MessageBox mostrando;


Puedes intentar esto:

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


Una solución que funciona en 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);

En función del efecto, al cerrar el formulario que posee el cuadro de mensaje también se cerrará el cuadro.

Los controles de Windows Forms tienen el requisito de que se debe acceder a ellos en el mismo hilo que los creó. El uso de TaskScheduler.FromCurrentSynchronizationContext() lo asegurará, suponiendo que el código de ejemplo anterior se ejecuta en el subproceso de la interfaz de usuario, o un subproceso creado por el usuario. El ejemplo no funcionará correctamente si el código se ejecuta en un subproceso de un grupo de subprocesos (por ejemplo, una devolución de llamada de temporizador) o un grupo de tareas (por ejemplo, en una tarea creada con TaskFactory.StartNew o Task.Run con los parámetros predeterminados).


RogerB en CodeProject tiene una de las soluciones más hábiles para esta respuesta, y lo hizo en el 2004, y sigue siendo explosivo

Básicamente, ve aquí a su proyecto y descarga el archivo CS . En caso de que ese enlace muera alguna vez, tengo una gist respaldo aquí. Agregue el archivo CS a su proyecto, o copie / pegue el código en alguna parte si prefiere hacerlo.

Entonces, todo lo que tendrías que hacer es cambiar

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

a

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

Y estás listo para ir.