Prism と Managed Extensibility Framework を使用して、WPF でアプリケーションを作成しています。目的は、開発者が独自のサードパーティ モジュールを作成できるようにすることです。できるだけ多くの作業を削除するために、必要な作業のほとんどを既に行っている共通モジュールにいくつかの基本クラスを作成しました。(例: ビューのドラッグ アンド ドロップ、 MEF の追加InheritedExportAttribute
)。これらのコントロールの 1 つは、以下に示すように呼び出されますModuleControl
(から派生しUserControl
ます)。
UserControl
XAMLで 1 つの子から直接派生したビュー クラスがモジュールにある場合、すべてがうまく機能します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();
}
}
Prism 4 アプリケーション チェックリストの例に従って、必要に応じて Unity の代わりに MEF を使用するようにこれを変更して、次のモジュールを作成しました。
このモジュールは 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() { }
}
}