我目前正在使用Prism 6在WPF App上工作......我有ShellViewModel
,ViewAViewModel
和ViewBViewModel
。
在Shell.xaml
内,我定义了"mainRegion"
。启动应用后,我默认会在该区域显示ViewA
。
现在,当我从ViewA
转到ViewB
时,此时(内部ViewBViewModel
),我需要有ShellViewModel
的上下文。
有任何建议要实现这一目标吗?
答案 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>();
}
}
}
这个解决方案由Brian Lagunas(棱镜所有者)在他的Pluralsight课程中提供(Prism Problems&amp; Solutions:Loading Dependent Views),** **还有另一种解决方案可以解决这个问题,https://www.youtube.com/watch?v=xH6OgCxdXQc,但我认为第一个解决方案是最好的和最简单的
在内容区域中注入的视图可以注入任意数量的选项卡,请参阅ViewB.xaml.cs中的注释