我正在使用 Prism 和 Managed Extensibility Framework 编写带有 WPF 的应用程序。目的是允许开发人员在那里创建自己的第 3 方模块。为了尽可能多地删除工作,我在一个 Common 模块中创建了一些基类,这些基类已经完成了大部分所需的工作。(例如,拖放视图,添加 MEF InheritedExportAttribute
)。这些控件之一称为ModuleControl
(派生自UserControl
),如下所示。
如果我的模块有一个直接派生自XAML 中的UserControl
一个孩子的视图类,那么我的一切工作都很好ModuleControl
(参见下面的示例)。这对用户来说似乎是很多额外的工作。我想让我的视图类仅使用代码从“ModuleControl”派生。如果我按照下面的最后一个示例执行此操作,则 RegisterViewWithRegion 将引发以下异常:
Activation error occured while trying to get instance of type ModuleView, key \"\"
System.Exception {Microsoft.Practices.ServiceLocation.ActivationException}
我意识到当类型无法注册时会发生这种情况。所以我的问题是我怎样才能做到这一点?我究竟做错了什么?RegisterViewWithRegion 是否明确期望 UserControl 并没有从中派生任何东西?
这是我位于 Common.dll 中的第一个控件的示例。
namespace Common.Controls
{
[InheritedExport]
public partial class ModuleControl: UserControl
{
private Point _anchor;
public ModuleControl()
{
InitializeComponent();
}
public ObservableCollection<IComponent> ModuleComponents
{
get
{
return (ObservableCollection<IComponent>)GetValue(ModuleComponentsProperty);
}
set
{
SetValue(ModuleComponentsProperty, value);
}
}
private void InitialiseCollection()
{
try
{
ModuleComponents = new ObservableCollection<IComponent>();
var components = ServiceLocator.Current.GetAllInstances(typeof(IComponent));
Assembly controlAssembly = UIHelper.FindAncestor<UserControl>(VisualTreeHelper.GetParent(this)).GetType().Assembly;
foreach (IComponent c in components)
{
if (c.ExportType.Assembly.Equals(controlAssembly))
{
ModuleComponents.Add(new Component(c.ViewType, c.Description));
}
}
}
catch (Exception e)
{
}
}
public string ModuleName
{
get
{
return (string)GetValue(ModuleNameProperty);
}
set
{
SetValue(ModuleNameProperty, value);
}
}
public static readonly DependencyProperty ModuleComponentsProperty =
DependencyProperty.Register("ModuleComponents", typeof(ObservableCollection<IComponent>), typeof(ModuleControl), new UIPropertyMetadata(null));
public static readonly DependencyProperty ModuleNameProperty =
DependencyProperty.Register("ModuleName", typeof(String), typeof(ModuleControl), new UIPropertyMetadata("No Module Name Defined"));
private void DragList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Store the mouse position
_anchor = e.GetPosition(null);
}
private void DragList_PreviewMouseMove(object sender, MouseEventArgs e)
{
// Get the current mouse position
Point mousePos = e.GetPosition(null);
Vector diff = _anchor - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
{
// Get the dragged ListViewItem
ListView listView = sender as ListView;
ListViewItem listViewItem = UIHelper.FindAncestor<ListViewItem>((DependencyObject)e.OriginalSource);
// Initialize the drag & drop operation
if (listViewItem != null)
{
DataObject dragData = new DataObject("moduleFormat", listViewItem.Content);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Move);
}
}
}
private void moduleControl_LayoutUpdated(object sender, EventArgs e)
{
if (ModuleComponents == null)
InitialiseCollection();
}
}
根据示例A Prism 4 Application Checklist,我构建了以下模块,将其修改为在适当的情况下使用 MEF 而不是 Unity:
该模块位于 RandomNumbers.dll
namespace RandomNumbers
{
[ModuleExport(typeof(RandomNumberModule))]
public class RandomNumberModule: IModule
{
public void Initialize()
{
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
regionManager.RegisterViewWithRegion("MyRegion", typeof(ModuleView));
}
}
}
有效的ModuleView
XAML 如下所示:
<UserControl x:Name="userControl" x:Class="RandomNumbers.Views.ModuleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:common="clr-namespace:Common.Base;assembly=Common"
xmlns:commonctrls="clr-namespace:Common.Controls;assembly=Common"
mc:Ignorable="d">
<commonctrls:ModuleControl x:Name="moduleControl" ModuleName="Random Number Module" />
</UserControl>
其背后的代码是:
namespace RandomNumbers.Views
{
[Export]
public partial class ModuleView : UserControl
{
private Point startPoint;
public ModuleView()
{
InitializeComponent();
}
}
}
如前所述,上述所有代码都可以完美运行。但是,如果我用它替换 XAML 和后面的代码,那么我会得到所描述的异常。我试过省略ExportAttribute
但没有任何改变。
namespace RandomNumbers.Views
{
[Export(typeof(UserControl))]
public class ModuleView : ModuleControl
{
public ModuleView() : base() { }
}
}