Prism 6在其他viewModel中获取ShellViewModel Context

时间:2016-04-03 13:47:30

标签: prism

我目前正在使用Prism 6在WPF App上工作......我有ShellViewModelViewAViewModelViewBViewModel

Shell.xaml内,我定义了"mainRegion"。启动应用后,我默认会在该区域显示ViewA

现在,当我从ViewA转到ViewB时,此时(内部ViewBViewModel),我需要有ShellViewModel的上下文。

有任何建议要实现这一目标吗?

1 个答案:

答案 0 :(得分:0)

完整的源代码!

<强> ViewA.xaml

<UserControl x:Class="ModuleA.Views.ViewA" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" > <TextBlock Text="{Binding Title}" FontSize="38" /> <Button Command="{Binding UpdateCommand}" Width="100">Update</Button> </StackPanel> </Grid> </UserControl>

<强> ViewA.xaml.cs

using ModuleA.RibbonTabs;
using PrismDemo.Core;
using System.Windows.Controls;
namespace ModuleA.Views
{
  [RibbonTab(typeof(ViewATab))]
  public partial class ViewA : UserControl, ISupportDataContext
  {
    public ViewA()
    {
        InitializeComponent();
    }
  }
}

<强> ViewB.xaml

<UserControl x:Class="ModuleA.Views.ViewB" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" > <TextBlock Text="{Binding Title}" FontSize="38" /> <Button Command="{Binding UpdateCommand}" Width="100">Update</Button> </StackPanel> </Grid> </UserControl>

<强> ViewB.xaml.cs

using ModuleA.RibbonTabs;
using PrismDemo.Core;
using System.Windows.Controls;
namespace ModuleA.Views
{
[RibbonTab(typeof(ViewBTab))]
//the main view can inject any number of tab 
//uncomment the following lines and test
//I added the same tab just for demo purposes
//[RibbonTab(typeof(ViewBTab))]
//[RibbonTab(typeof(ViewBTab))]
//[RibbonTab(typeof(ViewBTab))]
public partial class ViewB : UserControl, ISupportDataContext
{
    public ViewB()
    {
        InitializeComponent();
    }
}
}

<强> ModuleAModule.cs

using Microsoft.Practices.Unity;
using ModuleA.Views;
using Prism.Modularity;
using Prism.Unity;

namespace ModuleA
{
    public class ModuleAModule : IModule
    {
        IUnityContainer _container;

        public ModuleAModule(IUnityContainer container)
        {
            _container = container;
        }

        public void Initialize()
        {
            //register for nav
            _container.RegisterTypeForNavigation<ViewA>();
            _container.RegisterTypeForNavigation<ViewB>();
        }
    }
}

<强> RibbonTabAttribute.cs

using System;

namespace PrismDemo.Core
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public class RibbonTabAttribute : Attribute
    {
        public Type Type { get; private set; }

        public RibbonTabAttribute(Type ribbonTabType)
        {
            Type = ribbonTabType;
        }
    }
}

<强> ISupportDataContext.cs

namespace PrismDemo.Core
{
    public interface ISupportDataContext
    {
        object DataContext { get; set; }
    }
}

<强> bootstrapper.cs

using Prism.Unity;
using PrismDemo.Views;
using System.Windows;
using Microsoft.Practices.Unity;
using Prism.Modularity;
using ModuleA;
using Prism.Regions;
using PrismDemo.Prism;
using System.Windows.Controls.Ribbon;

namespace PrismDemo
{
    class Bootstrapper : UnityBootstrapper
    {
        protected override DependencyObject CreateShell()
    {
        return Container.Resolve<Shell>();
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }

    protected override void ConfigureModuleCatalog()
    {
        var catalog = (ModuleCatalog)ModuleCatalog;
        catalog.AddModule(typeof(ModuleAModule));
    }

    protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
    {
        var behaviors = base.ConfigureDefaultRegionBehaviors();
        behaviors.AddIfMissing(RibbonRegionBehavior.BehaviorKey, typeof(RibbonRegionBehavior));
        return behaviors;
    }
   }
}

<强>的App.xaml

<Application x:Class="PrismDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PrismDemo">
<Application.Resources>
</Application.Resources>
</Application>

<强> App.xaml.cs

using System.Windows;
namespace PrismDemo
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var bs = new Bootstrapper();
            bs.Run();
        }
    }
}

<强> Shell.xaml

<Window  x:Class="PrismDemo.Views.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="Shell" Height="720" Width="1280">
<Grid>
<Grid.RowDefinitions>
    <RowDefinition Height="auto"></RowDefinition>
    <RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Ribbon Grid.Row="0" prism:RegionManager.RegionName="RibbonTabRegion"/>
<DockPanel LastChildFill="True" Grid.Row="1">
    <StackPanel>
        <Button Content="Navigate ViewA" Command="{Binding NavigateCommand}" CommandParameter="ViewA" />
        <Button Content="Navigate ViewB" Command="{Binding NavigateCommand}" CommandParameter="ViewB" />
    </StackPanel>
    <ContentControl prism:RegionManager.RegionName="ContentRegion" Margin="1,3,3,3" />
</DockPanel>
</Grid>
</Window>

<强> Shell.xaml.cs

namespace PrismDemo.Views
{
    public partial class Shell 
    {
        public Shell()
        {
            InitializeComponent();
        }
    }
}

<强> ShellViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;

namespace PrismDemo.ViewModels
{
public class ShellViewModel : BindableBase
{
    IRegionManager _regionManager;

    public DelegateCommand<string> NavigateCommand { get; set; }

    public ShellViewModel(IRegionManager regionManager)
    {
        _regionManager = regionManager;

        NavigateCommand = new DelegateCommand<string>(Navigate);
    }

    void Navigate(string navigationPath)
    {
        _regionManager.RequestNavigate("ContentRegion", navigationPath);
    }
}
}

<强> RibbonRegionBehavior.cs

using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Specialized;
using PrismDemo.Core;
using System.Windows.Controls.Ribbon;

namespace PrismDemo.Prism
{
public class RibbonRegionBehavior : RegionBehavior
{
    public const string BehaviorKey = "RibbonRegionBehavior";

    public const string RibbonTabRegionName = "RibbonTabRegion";

    protected override void OnAttach()
    {
        if (Region.Name == "ContentRegion")
            Region.ActiveViews.CollectionChanged += ActiveViews_CollectionChanged;
    }

    private void ActiveViews_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            var tabList = new List<RibbonTab>();

            foreach (var newView in e.NewItems)
            {
                foreach (var atr in GetCustomAttributes<RibbonTabAttribute>(newView.GetType()))
                {
                    var ribbonTabItem = Activator.CreateInstance(atr.Type) as RibbonTab;

                    if (ribbonTabItem is ISupportDataContext && newView is ISupportDataContext)
                        ((ISupportDataContext)ribbonTabItem).DataContext = ((ISupportDataContext)newView).DataContext;

                    tabList.Add(ribbonTabItem);
                }

                tabList.ForEach(x => Region.RegionManager.Regions[RibbonTabRegionName].Add(x));
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            var views = Region.RegionManager.Regions[RibbonTabRegionName].Views.ToList();
            views.ForEach(x => Region.RegionManager.Regions[RibbonTabRegionName].Remove(x));
        }
    }

    private static IEnumerable<T> GetCustomAttributes<T>(Type type)
    {
        return type.GetCustomAttributes(typeof(T), true).OfType<T>();
    }
 }
}

这是演示应用的结构: Structure of the demo app

这个解决方案由Brian Lagunas(棱镜所有者)在他的Pluralsight课程中提供(Prism Problems&amp; Solutions:Loading Dependent Views),** **还有另一种解决方案可以解决这个问题,https://www.youtube.com/watch?v=xH6OgCxdXQc,但我认为第一个解决方案是最好的和最简单的

在内容区域中注入的视图可以注入任意数量的选项卡,请参阅ViewB.xaml.cs中的注释