Mostrar Form desde otro hilo

26/08/2008 - 22:36 por Ignacio X. Domínguez | Informe spam
Un saludo a toda la comunidad.

Estoy desarrollando una aplicacíón de notificación que coloca un icono en la
bandeja y muestra una ventana de notificación cuando ocurre un evento al
estilo messenger y es la clase principal la que maneja el GUI. Tengo además
otra clase con un hilo que cada cierto tiempo llama a un Web Service. Cuando
este servicio devuelve algunos datos la idea es mostrar la ventana de
notificacion. El problema esta en que cuando se llama el metodo que muestra
la ventana la ventana se crea pero no esta visible. Si hago en cambio doble
click sobre el icono (el evento llama al mismo metodo) la ventana se muestra
perfectamente. El problema creo que esta en que la ventana creada desde el
hilo de notificaciones usa el mismo hilo y no el hilo del thread. Intente
solucionarlo con un delegate y un evento, luego llamando al metodo Invoke,
pero no funciona.

Les muestro el codigo simplificado para ilustrar:

class Notifier : ApplicationContext {
private System.ComponentModel.IContainer components = null;
private NotifyIcon trayIcon;
private ContextMenuStrip trayMenu;

private NotificationChecker nc = null;

[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Notifier());
}

public Notifier() {
this.components = new System.ComponentModel.Container();
this.trayIcon = new NotifyIcon(this.components);
this.trayMenu = new ContextMenuStrip(this.components);
this.trayIcon.ContextMenuStrip = this.trayMenu;
this.trayIcon.DoubleClick += new EventHandler(trayIcon_DoubleClick);
this.trayIcon.Visible = true;
nc = new NotificationChecker();
nc.NotificationsArrived += new
NotificationsArrivedEventHandler(showNotificationForm);
nc.startChecking();
}

private void trayIcon_DoubleClick(object sender, EventArgs e) {
showNotificationForm();
}

private void showNotificationForm() {
frmNotification fAlert = new frmNotification();
fAlert.Show();
}
}


Ahora el codigo del hilo que llama al web service:



public delegate void NotificationsArrivedEventHandler();

class NotificationChecker {
private Thread thread = null;
private bool started = false;
private NotifierWebService unWebService = null;

public event NotificationsArrivedEventHandler NotificationsArrived;

public NotificationChecker() {
started = false;
unWebService = new NotifierWebService();
unWebService.getNotificationsCompleted += new
getNotificationsCompletedEventHandler(notificationsArrived);
}

private void run() {
while(started) {
unWebService.getNotificationsAsync(settings.UserLogin,
settings.UserPassword);
Thread.Sleep(600000);
}
}

private void notificationsArrived(object sender,
getNotificationsCompletedEventArgs e) {
if(e.Error != null) {
return;
}
else if(e.Result.Length > 0) {
if(NotificationsArrived != null)
NotificationsArrived.Invoke();
}
}

public void startChecking() {
if(!started) {
started = true;
thread = new Thread(new ThreadStart(run));
thread.IsBackground = true;
thread.Start();
}
}

public void stopChecking() {
if(started) {
started = false;
thread.Interrupt();
thread.Abort();
thread = null;
}
}
}


Alguien tiene alguna idea? Gracias de antemano
 

Leer las respuestas

#1 RFOG
27/08/2008 - 10:51 | Informe spam
No he visto tu código en detalle (ya tengo bastante con ver el mío, je
je), pero la forma correcta de tocar código de la UI desde otro hilo
aparte del principal es el de ejecutar ese código desde un método llamado
mediante Invoke.

Luego está el tema de que no te aparece esa ventana. Si lo haces como
arriba seguro que te está apareciendo, lo que ocurre es que al estar el
usuario trabajando con otras, aparece y queda tapada. Para evitarlo,
tienes que poner la propiedad TopMost de la misma a true.

On Tue, 26 Aug 2008 22:36:33 +0200, Ignacio X. Domínguez
wrote:

Un saludo a toda la comunidad.

Estoy desarrollando una aplicacíón de notificación que coloca un icono
en la bandeja y muestra una ventana de notificación cuando ocurre un
evento al estilo messenger y es la clase principal la que maneja el
GUI. Tengo además otra clase con un hilo que cada cierto tiempo llama a
un Web Service. Cuando este servicio devuelve algunos datos la idea es
mostrar la ventana de notificacion. El problema esta en que cuando se
llama el metodo que muestra la ventana la ventana se crea pero no esta
visible. Si hago en cambio doble click sobre el icono (el evento llama
al mismo metodo) la ventana se muestra perfectamente. El problema creo
que esta en que la ventana creada desde el hilo de notificaciones usa el
mismo hilo y no el hilo del thread. Intente solucionarlo con un delegate
y un evento, luego llamando al metodo Invoke, pero no funciona.

Les muestro el codigo simplificado para ilustrar:

class Notifier : ApplicationContext {
private System.ComponentModel.IContainer components = null;
private NotifyIcon trayIcon;
private ContextMenuStrip trayMenu;

private NotificationChecker nc = null;

[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Notifier());
}

public Notifier() {
this.components = new System.ComponentModel.Container();
this.trayIcon = new NotifyIcon(this.components);
this.trayMenu = new ContextMenuStrip(this.components);
this.trayIcon.ContextMenuStrip = this.trayMenu;
this.trayIcon.DoubleClick += new
EventHandler(trayIcon_DoubleClick);
this.trayIcon.Visible = true;
nc = new NotificationChecker();
nc.NotificationsArrived += new
NotificationsArrivedEventHandler(showNotificationForm);
nc.startChecking();
}

private void trayIcon_DoubleClick(object sender, EventArgs e) {
showNotificationForm();
}

private void showNotificationForm() {
frmNotification fAlert = new frmNotification();
fAlert.Show();
}
}


Ahora el codigo del hilo que llama al web service:



public delegate void NotificationsArrivedEventHandler();

class NotificationChecker {
private Thread thread = null;
private bool started = false;
private NotifierWebService unWebService = null;

public event NotificationsArrivedEventHandler NotificationsArrived;

public NotificationChecker() {
started = false;
unWebService = new NotifierWebService();
unWebService.getNotificationsCompleted += new
getNotificationsCompletedEventHandler(notificationsArrived);
}

private void run() {
while(started) {
unWebService.getNotificationsAsync(settings.UserLogin,
settings.UserPassword);
Thread.Sleep(600000);
}
}

private void notificationsArrived(object sender,
getNotificationsCompletedEventArgs e) {
if(e.Error != null) {
return;
}
else if(e.Result.Length > 0) {
if(NotificationsArrived != null)
NotificationsArrived.Invoke();
}
}

public void startChecking() {
if(!started) {
started = true;
thread = new Thread(new ThreadStart(run));
thread.IsBackground = true;
thread.Start();
}
}

public void stopChecking() {
if(started) {
started = false;
thread.Interrupt();
thread.Abort();
thread = null;
}
}
}


Alguien tiene alguna idea? Gracias de antemano








Microsoft Visual C++ MVP
==Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y programación
Un pintor es un hombre que pinta lo que vende. Un artista, en cambio, es
un hombre que vende lo que pinta.

Preguntas similares