wpf mvvm events view viewmodel

WPF: ¿cómo señalar un evento desde ViewModel a View sin código en codebehind?



mvvm events (5)

Tengo un problema bastante simple (espero :)):

En MVVM, View generalmente escucha los cambios de las propiedades de ViewModel. Sin embargo, a veces me gustaría escuchar el evento para que, por ejemplo, View pueda iniciar la animación o cerrar la ventana cuando las señales de VM.

Hacerlo a través de la propiedad bool con NotifyPropertyChanged (y comenzar la animación solo cuando cambie de falso a verdadero) es posible, pero se siente como un truco, prefiero exponer el evento, ya que es semánticamente correcto.

Además, me gustaría hacerlo sin código en código subyacente, ya que al hacer viewModel.myEvent += handler significaría que habría anulado el registro manualmente del evento para permitir que View sea GC''d - Las vistas de WPF ya son capaces para escuchar las propiedades "débilmente", y preferiría programar solo de manera declarativa en View.

La suscripción al evento fuerte estándar también es mala, porque necesito cambiar varios modelos de vista para una vista (porque la creación de la vista cada vez requiere demasiado tiempo de la CPU).

Gracias por las ideas (si hay una solución estándar, bastará con un enlace a msdn).


Algunos comentarios:

  • Puede usar el patrón de eventos débiles para asegurarse de que la vista se pueda GC, incluso si todavía está adjunta al evento del modelo de visualización.
  • Si ya está cambiando varias máquinas virtuales para una vista, ¿no sería ese el lugar ideal para conectar / desconectar el controlador?
  • Dependiendo de su escenario exacto, puede hacer que la VM exponga una propiedad de estado que la vista utiliza como activador de animaciones, transiciones y otros cambios visuales. Visual State Manager es ideal para este tipo de cosas.

Como dijo Adrianm, cuando desencadenas la animación de una propiedad bool, en realidad estás respondiendo a un evento. Específicamente, el evento PropertyChanged que el subsistema WPF. Que está diseñado para conectarse / desconectarse correctamente de / para que no se pierda la memoria (puede olvidarse de hacer esto al cablear un evento usted mismo y causar una pérdida de memoria al tener una referencia activa a un objeto que de otra manera debería ser GC) .

Esto le permite exponer su ViewModel como DataContext para el control y responder correctamente al cambio de propiedades en el contexto de datos a través del enlace de datos.

MVVM es un patrón que funciona particularmente bien con WPF debido a todas estas cosas que WPF le brinda, y desencadenar un cambio de propiedad es en realidad una forma elegante de usar todo el subsistema WPF para lograr sus objetivos :)


Este hilo es bastante antiguo, pero proporcionaré mi $ 0.02 porque es algo con lo que luché también recientemente ...

Similar a lo que otros dicen, pero aquí hay un ejemplo con algunos fragmentos de código ... Este ejemplo muestra cómo usar pub / sub para tener una vista suscribirse a un evento activado por la máquina virtual, en este caso hago un GridView. Vuelva a conectar para asegurarse de que el gv esté sincronizado con la VM ...

Ver (Sub):

using Microsoft.Practices.Composite.Events; using Microsoft.Practices.Composite.Presentation.Events; private SubscriptionToken getRequiresRebindToken = null; private void SubscribeToRequiresRebindEvents() { this.getRequiresRebindToken = EventBus.Current.GetEvent<RequiresRebindEvent>() .Subscribe(this.OnRequiresRebindEventReceived, ThreadOption.PublisherThread, false, MemoryLeakHelper.DummyPredicate); } public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload) { if (payload != null) { if (payload.RequiresRebind) { using (this.gridView.DeferRefresh()) { this.gridView.Rebind(); } } } } private void UnsubscribeFromRequiresRebindEvents() { if (this.getRequiresRebindToken != null) { EventBus.Current.GetEvent<RequiresRebindEvent>() .Unsubscribe(this.getRequiresRebindToken); this.getRequiresRebindToken = null; } }

Llame a unsub desde el método de cierre para evitar fugas de memoria.

ViewModel (Pub):

private void PublishRequiresRebindEvent() { var payload = new RequiresRebindEventPayload(); payload.SetRequiresRebind(); EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload); }

Clase de carga útil

using System; using Microsoft.Practices.Composite.Presentation.Events; public class RequiresRebindEvent : CompositePresentationEvent<RequiresRebindEventPayload> { } public class RequiresRebindEventPayload { public RequiresRebindEventPayload() { this.RequiresRebind = false; } public bool RequiresRebind { get; private set; } public void SetRequiresRebind() { this.RequiresRebind = true; } }

Tenga en cuenta que también puede configurar el constructor para que pase en un Guid, o en algunos identificados en, que se puede configurar en Pub y se marcó en sub para asegurarse de que pub / sub esté sincronizado.


Una pregunta más general es: "¿Por qué estoy tratando de lidiar con este evento en mi ViewModel?"

Si la respuesta tiene algo que ver con elementos solo de vista como animaciones, argumentaría que ViewModel no necesita saber al respecto: el código subyacente (cuando corresponda), Data / Event / PropertyTriggers y las construcciones más nuevas de VisualStateManager le servirán mucho mejor. y mantener la separación limpia entre View y ViewModel.

Si algo tiene que "suceder" como resultado del evento, entonces lo que realmente quiere usar es un patrón de Comando, ya sea usando el CommandManger, manejando el evento en el código subyacente e invocando el comando en el modelo de vista, o usando comportamientos adjuntos en el sistema.Interactividad libs.

De cualquier manera, desea mantener su ViewModel lo más "puro" que pueda: si ve algo específico de View allí, probablemente lo esté haciendo mal. :)


Yo estoy separado

  1. state - para poder mover datos hacia atrás / adelante entre view <-> vm
  2. acciones - para poder llamar a ver funciones / comandos del modelo
  3. notificaciones: para poder indicarle a la vista que algo ha sucedido y que desee realizar una acción visual como hacer que un elemento brille, cambiar de estilos, cambiar el diseño, enfocar otro elemento, etc.

si bien es cierto que puede hacer esto con un enlace de propiedad, es más un hack que los tomas; Siempre me ha parecido así.

Mi solución para poder escuchar los ''eventos'' de un modelo de vista también conocido como notificaciones es simplemente escuchar los cambios en el contexto de datos y cuando cambia, verifico que el tipo es el que estoy buscando y conecto los eventos. crudo pero simple.

lo que realmente me gustaría es una forma simple de definir algunos desencadenantes de ''ver modelo de evento'' y luego proporcionarle algún tipo de controlador que reaccione en el lado de la vista de todas las cosas en el xaml y solo colocar el código detrás de las cosas que no sea do-able en xaml