Pregunta

Tengo un PropertyGrid en mi aplicación que se utiliza para la edición de objetos arbitrarios. Tengo que ser capaz de ejecutar una subrutina arbitraria en otro hilo que también se ve en estos objetos (funcionalidad de búsqueda, si tienes curiosidad). La cuestión obvia es que un usuario podría estar editando uno de los al mismo tiempo, estos objetos mi hilo de búsqueda es leerlo, lo que sería preferible evitar (aunque probablemente no resultará en nada crítico, ya que mi hilo de búsqueda es sólo lectura, no escribir).

Llamando lock(obj) es bastante fácil de mi hilo de búsqueda, pero después de mirar a través de la documentación y una breve descremada a través del código PropertyDescriptorGridEntry en el reflector, me parece que no puede encontrar un lugar análogo al utilizar una llamada System.Threading.Monitor.Enter()/Exit() en el objeto en cuestión en el PropertyGrid. Tenía la esperanza de que habría BeginEdit y EndEdit eventos que harían de esta bastante simple, pero me parece que no puede encontrar tal cosa. Yo prefiero no cierro todo el objeto mientras está en exhibición en el PropertyGrid ya que ello obviamente bloquear mi hilo de búsqueda hasta que se seleccione otro objeto.

Soy un poco nuevo en el modelo de subprocesos de Windows Forms, así que estoy esperando que hay alguna respuesta obvia que acabo de pasar por alto. Cualquier ayuda?

Editar síncrono clonación mis objetos antes de ejecutar la búsqueda asíncrona probablemente será suficiente ineficiente que yo también podría ejecutar la búsqueda en sí misma de forma sincrónica - el punto de ejecutar de forma asincrónica, por supuesto, para permitir que mis usuarios continuar trabajando mientras que la búsqueda se está ejecutando. La búsqueda tiene que escalar bien, como el conjunto de datos que estoy pasando con el tiempo llegar a ser arbitrariamente grande, lo que hace que la clonación sincrónica parezca que hará que el problema de usabilidad que estoy tratando de evitar.

¿Fue útil?

Solución

Creo que va a tener que hacer un poco de trabajo para esto.

En primer lugar, habría que crear una implementación de ICustomTypeDescriptor que basar su aplicación en cualquier TypeDescriptor que normalmente obtener de ese tipo.

A continuación, en las implementaciones de los métodos que exponen los descriptores de los miembros que desea bloquear en adelante, se le proporcionará subclases que se derivan de dichos elementos descriptivos y anular los métodos apropiados para envolver un bloqueo alrededor.

Así que para una propiedad, se llevaría a cabo GetProperties para regresar a sus subclases específicas de PropertyDescriptor. Estas subclases para prevalecer sobre los métodos GetValue y SetValue (y otros) y el uso de un bloqueo cuando se accede a dichas variables.

Se debe mencionar que el bloqueo de este tipo en el hilo de interfaz de usuario es probablemente una mala idea, ya que no desea bloquear arbitrariamente operaciones en ese hilo. Podría ser preferible crear un clon del objeto y luego tener un método que actualiza la tienda de objetos cuando haya terminado.

Otros consejos

Ese hecho no será seguro para subprocesos. Se podría reunir bits del código de búsqueda al hilo de interfaz de usuario, pero que va a ralentizar las cosas, y tal vez la derrota el punto de la rosca ...

¿A qué velocidad la búsqueda necesita ser? Se puede trabajar en contra de un clon? etc.

¿Se puede clonar los datos antes de mostrarla, y conseguir que su hilo de búsqueda para trabajar en el clon? Si desea que el hilo de búsqueda para "ver" cambios, se puede responder a eventos en el PropertyGrid y tal vez hacer controlado cambios en el clon de alguna manera. (Es probable que sea más fácil usar los datos "vieja" sin embargo.)

Sé que la clonación de datos suena terriblemente ineficiente, pero desde luego enhebrar más sencillo cuando cada hilo trabaja sobre datos completamente independientes (o todos los hilos de sólo lectura).

Podría estar equivocado, pero me parece que viene desde el extremo equivocado.

Hay dos cuestiones distintas que necesita para hacer frente a.

En primer lugar, asegurándose de que el PropertyGrid sólo es accesible siempre en el hilo de interfaz de usuario. Si cualquiera de sus métodos (incluyendo propiedades getter / setters) son accesibles desde otros hilos, vas a sufrir el dolor de manera misteriosa. Las excepciones son InvokeRequired() y Invoke, por supuesto.

En segundo lugar, asegurándose de que su hilo de búsqueda puede funcionar correctamente.

Para resolver el primer problema, o bien hacen que sus objetos no se modifican excepto por el hilo de interfaz de usuario, o que todos los de su evento disparadores hilo cuenta para que sus eventos objetos (tales como PropertyChanged) no se activa nunca en el hilo de interfaz de usuario.

El segundo problema es más fácil - siempre y cuando el hilo de búsqueda sólo se lee de sus objetos principales, todo debería funcionar bien. Sí, el hilo de búsqueda podría inadvertidamente ver algunos datos actualizados parcialmente, pero es que realmente un problema?

Un par de reflexiones finales ...

  • No poner en práctica su búsqueda para iterar a través de la misma PropertyGrid; obtener una lista de los objetos en la delantera (que no necesitan ser clones) y trabajar a través de ese lugar.

  • Ha considerado el uso de procesamiento de inactividad para hacer la búsqueda? El objeto Application dispara un evento cada vez que se ejecuta la aplicación de mensajes a proceso - se puede enganchar en esto y realizar el paso 1 de su búsqueda cada vez que se dispara el evento. Una especie de mala Mans roscado, pero con ninguno de los dolores de cabeza mutex / bloqueo / semaphone. He utilizado este con muy buenos resultados en el pasado.

Actualizar : Si no recuerdo mal, PropertyGrid respeta la interfaz IEditableObject, llamando BeginEdit tan pronto como empiece a modificar una fila, y EndEdit cuando se mueve a una fila diferente. Se podría aprovechar esto para evitar que el hilo de la búsqueda de ver cambios incompletos.

Actualización 2 : seguimiento, he descubierto lo que ya sabía - que PropertyGrid no respetar la interfaz IEditableObject.

Tengo otra sugerencia - aunque podría ser más trabajo que desea invertir.

Alrededor del momento en que el espacio de nombres System.Transactions se introdujo en .NET 2,0, vi un artículo sobre el uso de la transacción ambiente para proporcionar hilos de aislamiento para objetos. La idea es que sus propiedades de los objetos tienen doble almacenamiento. En primer lugar usted tiene el valor comprometido, visible para todos los temas, y usted tiene una variable de subproceso local se utiliza para almacenar los valores comprometidos en una base por hilo. Cuando una propiedad es modificada, el objeto se alista en cualquier transacción ambiente almacenando el nuevo valor en el hilo local. Cuando la transacción confirma o deshace, el valor para el hilo se almacena o se desecha.

Por desgracia, no puedo encontrar el artículo original, aunque parece que CSLA ofrece este apoyo. Espero que esto ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top