WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate] WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate] wpf wpf

WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate]


Some comments:

  • You can use the weak event pattern to ensure that the view can be GC'd even if it is still attached to the view model's event
  • If you're already switching multiple VMs in for the one view, wouldn't that be the ideal place to attach/detach the handler?
  • Depending on your exact scenario, you could just have the VM expose a state property which the view uses as a trigger for animations, transitions, and other visual changes. Visual state manager is great for this kind of thing.


This is something that I wrestled with as well...

Similar to what others are saying, but here is an example with some code snippets... This example shows how to use pub/sub to have a View subscribe to an event fired by the VM - in this case I do a GridView. Rebind to ensure the gv is in sync with the VM...

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

Call unsub from the close method to prevent memory leaks.

ViewModel (Pub):

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

Payload class

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

Note that you can also set the constructor up to pass in a Guid, or some identified in, which can be set on Pub and checked on sub to be sure pub/sub is in sync.


A more general question to ask is: "Why am I trying to deal with this event in my ViewModel?"

If the answer has anything to do with view-only things like animations, I'd argue the ViewModel needs not know about it: code behind (when appropriate), Data/Event/PropertyTriggers, and the newer VisualStateManager constructs will serve you much better, and maintain the clean separation between View and ViewModel.

If something needs to "happen" as a result of the event, then what you really want to use is a Command pattern - either by using the CommandManger, handling the event in code behind and invoking the command on the view model, or by using attached behaviors in the System.Interactivity libs.

Either way, you want to keep your ViewModel as "pure" as you can - if you see anything View-specific in there, you're probably doing it wrong. :)