开发者

Prism 4 - locally scoped RegionManager

I have silverlight 4 application with PRISM 4, I'm using MEF.

My Shell defines one main region in which modules are loaded, I want modules to have their own RegionManager, so regions that they define are places in local RegionManager instead of globa开发者_如何学运维l. And I want this local RegionManager to be resolved by container (for type IRegionManager) when inside the module.

However the method from documentation:

IRegion detailsRegion = this.regionManager.Regions["DetailsRegion"];
View view = new View();
bool createRegionManagerScope = true;
IRegionManager detailsRegionManager = detailsRegion.Add(view, null, 
                            createRegionManagerScope);

Doesnt work for me, when resolving IRegionManager from inside child view I still get GlobalRegionManager.


I was in the same situation as you, I had a nested region manager, but all of the child views were still getting the global region manager. I came up with what I consider a reasonable solution.

First I define an interface:

/// <summary>
/// An interface which is aware of the current region manager.
/// </summary>
public interface IRegionManagerAware
{
    /// <summary>
    /// Gets or sets the current region manager.
    /// </summary>
    /// <value>
    /// The current region manager.
    /// </value>
    IRegionManager RegionManager { get; set; }
}

Then I setup a RegionBehavior like so:

/// <summary>
/// A behaviour class which attaches the current scoped <see cref="IRegionManager"/> to views and their data contexts.
/// </summary>
public class RegionAwareBehaviour : RegionBehavior
{
    /// <summary>
    /// The key to identify this behaviour.
    /// </summary>
    public const string RegionAwareBehaviourKey = "RegionAwareBehaviour";

    /// <summary>
    /// Override this method to perform the logic after the behaviour has been attached.
    /// </summary>
    protected override void OnAttach()
    {
        Region.Views.CollectionChanged += RegionViewsChanged;
    }

    private void RegionViewsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Contract.Requires<ArgumentNullException>(e != null);

        if (e.NewItems != null)
            foreach (var item in e.NewItems)
                MakeViewAware(item);
    }

    private void MakeViewAware(object view)
    {
        Contract.Requires<ArgumentNullException>(view != null);

        var frameworkElement = view as FrameworkElement;
        if (frameworkElement != null)
            MakeDataContextAware(frameworkElement);

        MakeAware(view);
    }

    private void MakeDataContextAware(FrameworkElement frameworkElement)
    {
        Contract.Requires<ArgumentNullException>(frameworkElement != null);

        if (frameworkElement.DataContext != null)
            MakeAware(frameworkElement.DataContext);
    }

    private void MakeAware(object target)
    {
        Contract.Requires<ArgumentNullException>(target != null);

        var scope = target as IRegionManagerAware;
        if (scope != null)
            scope.RegionManager = Region.RegionManager;
    }
}

Then apply this to all regions in your bootstrapper:

protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
    var behaviours = base.ConfigureDefaultRegionBehaviors();

    behaviours.AddIfMissing(RegionAwareBehaviour.RegionAwareBehaviourKey, typeof(RegionAwareBehaviour));

    return behaviours;
}

Then all you have to do is implement IRegionManagerAware on your view/viewmodel, probably like so:

public class MyView : IRegionManagerAware
{
    IRegionManager RegionManager { set; get; }
}

Then when this view is added to a region, the behaviour will correctly set the RegionManager property to the currently scoped region manager.


If you read the next line in the documentation it says "The Add method will return the new RegionManager that the view can retain for further access to the local scope."

so I would create a property in the view and pass the IRegionManger to it.

inside your view/viewModel.

public IRegionManager rm { get; set; }

then pass the IregionManager which was returned after adding the new view

view.rm = detailsRegionManager;

Hope that helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜