views:

405

answers:

3

I'm using the CAG and I've got some issues using the TabControl region. I worked out that by marking the view (and NOT the PresentationModel) as IActiveAware I can get an event when the view is activated/deactivated. That works well when the composite is simple and the TabItem is the view.

However, in my case I've got a composite inside the TabItem. It can listen to activation events but I'd like to propagate these events to its children so that they can react to them. Is there a way of doing that? I had a look at the RegionContext but it doesn't seem to work in my case (or maybe I'm doing it wrong).

Could it be that I'm missing out on something and an attached dependency or something else would solve my issue?

A: 

Have you looked at Prism EventAggregator? This can be implemented as some sort of MessageBus or Mediator... You can Puplish events and everyone who needs be interested can subscribe to it... If you look in the prism samples you find an implementation or something in the docs...

silverfighter
I could but then I would have to pass on a lot of information to the child views to work out whether or not its their parent that got activated :(
R4cOON
A: 

The Prism EventAggregator (EA) object allows you to publish events and subscribe to them through the EA object. This can be used with a single publisher and 0, 1 or many subscribers. I generally use the EA when I need to communicate between different parts of an application that are not tied together. For example, a menu item in the shell of a Prism application may need to invoke another view in a different module. The EA allows you to do this via pub/sub. However if a screen needs to make something happen on its own self, this ifs often better suited for the Command object.

John Papa
A: 

I decided to use the RegionContext to propagate the IsActive state within the region.

Set it up as:

    Regions:RegionManager.RegionContext="{Binding Path=IsActive, Mode=TwoWay}"

on my tab view (which is IActiveAware). Then in the child view I can listen to changes:

    RegionContext.GetObservableContext((DependencyObject)View).PropertyChanged += new PropertyChangedEventHandler(VehiclesPresentationModel_PropertyChanged);


private void VehiclesPresentationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Value")
    {
        IsActive = (bool)RegionContext.GetObservableContext((DependencyObject)View).Value;
    }
}

The remaining issue was that the reverse would work. Setting IsActive on the tab view doesn't active the tab :( I added a custom behavior and now it works. The custom bahavior is like:

public class RegionReverseActiveAwareBehavior : RegionBehavior
{
    public const string BehaviorKey = "RegionReverseActiveAwareBehavior";


    protected override void OnAttach()
    {
        Region.Views.CollectionChanged += new NotifyCollectionChangedEventHandler(Views_CollectionChanged);
    }


    private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (var item in e.NewItems)
            {
                IActiveAware activeAwareItem = item as IActiveAware;
                if (activeAwareItem != null)
                {
                    activeAwareItem.IsActiveChanged += new EventHandler(activeAwareItem_IsActiveChanged);
                }
            }
        }
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (var item in e.OldItems)
            {
                IActiveAware activeAwareItem = item as IActiveAware;
                if (activeAwareItem != null)
                {
                    activeAwareItem.IsActiveChanged -= new EventHandler(activeAwareItem_IsActiveChanged);
                }
            }
        }
    }

    private void activeAwareItem_IsActiveChanged(object sender, EventArgs e)
    {
        IActiveAware activeAware = sender as IActiveAware;
        if (activeAware != null &&
            activeAware.IsActive)
        {
            Region.Activate(activeAware);
        }
    }
}

And then I set it up on the TabControl with:

        RegionManager.GetObservableRegion(tabRegion).PropertyChanged +=
            (sender, args) =>
                {
                    if (args.PropertyName == "Value")
                    {
                        IRegion region = RegionManager.GetObservableRegion(tabRegion).Value;
                        region.Behaviors.Add(RegionReverseActiveAwareBehavior.BehaviorKey, new RegionReverseActiveAwareBehavior());
                    }
                };

Hope that solves someone else's issue. Or maybe there's an easier way that I'm missing.

R4cOON