2011-08-28 45 views
7

Tengo una clase de servidor que básicamente espera las conexiones de un cliente. Dentro de esa clase creo un objeto NetworkStream para poder recibir bytes de un cliente. Como el método NetworkStream.Read() no es asíncrono (lo que significa que esperará hasta que lea bytes de un cliente para continuar ejecutando código similar al método messagebox), tendré que leer los bytes en un hilo separado para que el el usuario que usa el programa aún puede interactuar con el programa si el programa está esperando a leer datos.objeto de acceso desde un hilo diferente

de todos modos un montón de objetos son propiedad de ese hilo. Un ejemplo es que tengo una lista llamada iniciar sesión en esa clase. Utilizo esa lista para conocer el estado del servidor. Tal vez está escuchando una conexión o tal vez su estado está "conectado" o "desconectado".

Así que si hago algo como:

Server myServer = new Server("192.168.0.120","1300"...\\ I pass the appropite parameters in order to instantiate it 

//... 
.. then I am able to latter look at the log as 
string foo = myServer.Log[0] for example. 

porque quiero saber cuando se actualiza el registro, en el servidor de clase I se ha creado un evento como:

public delegate void onUpdateHandler(string newStatus); 
    public event onUpdateHandler onUpdate = delegate { }; 

entonces el fuego eventos en la clase de servidor como:

onUpdate("waitingForConnection"); 

y recibo esos eventos con el método:

enter image description here

pero si trato de hacer algo con nuevoCondición recibo indicando el error:

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it. 

así que ¿cómo puedo pasar un objeto con un evento?


Editar

así que también cuenta de que si lo hago:

enter image description here

también consigo un error!

pero cuando lo haga lo mismo que llamar desde un botón como:

// SERVER IS RUNNING BEFORE CALLING THIS METHOD 
    private void button3_Click(object sender, RoutedEventArgs e) 
    { 

     listView1.Items.Add("my own string"); 

    } 

No consigo un error!

por qué es que me sale un error con el evento y no aparece un error al llamarlo con un botón normal.

Respuesta

12

El problema es que el hilo intenta acceder a la ListView que es un DependencyObject que tiene afinidad hilo, utilice el Dispatcher para ejecutar los métodos de este tipo en la interfaz de usuario de rosca, por ejemplo:

Application.Current.Dispatcher.Invoke((Action)(() => 
{ 
    listView1.Items.Add(newStatus); 
})); 

Véase también la threading model reference para obtener información adicional.

+0

cuando coloco que en el interior mi método me da un error que dice: No se puede convertir la expresión lambda para escribir 'System.Delegate' porque no es un tipo de delegado –

+0

@TonoNam: Oh sí, tienes que lanzarlo, o crear una acción explícitamente. –

+0

@Tono, el lambda tiene que ser enviado a algún tipo de delegado, ver mi edición. – svick

1

El problema no es que trates de hacer algo con el valor que enviaste al método, el problema es lo que estás tratando de hacer con él.

El controlador de eventos todavía se está ejecutando en el hilo de fondo, y desde allí no puede usar ningún control de UI ya que pertenecen al hilo principal.

La forma más habitual de tratamiento que se va a utilizar el método CheckAccess para comprobar si necesita cambiar de bandas de rodadura, y el método Invoke a mano de la obra al hilo principal:

void server_onUpdate(string newStatus) { 
    if (!listView1.Dispatcher.CheckAccess()) { 
    listView1.Dispatcher.Invoke(server_onUpdate, newStatus) 
    } else { 
    listView1.Items.Add(newStatus); 
    } 
} 
+0

Según las etiquetas esto no es WinForms ... –

+0

@ H.B .: Ya lo corrigí. – Guffa

+0

@Guffa buena explicación gracias –

Cuestiones relacionadas